dependabot-npm_and_yarn 0.248.0 → 0.250.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/dependency_files_filterer.rb +47 -19
- data/lib/dependabot/npm_and_yarn/file_fetcher/path_dependency_builder.rb +54 -20
- data/lib/dependabot/npm_and_yarn/file_fetcher.rb +105 -58
- data/lib/dependabot/npm_and_yarn/file_parser/json_lock.rb +20 -2
- data/lib/dependabot/npm_and_yarn/file_parser/lockfile_parser.rb +35 -16
- data/lib/dependabot/npm_and_yarn/file_parser/yarn_lock.rb +3 -2
- data/lib/dependabot/npm_and_yarn/file_parser.rb +94 -31
- data/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb +4 -1
- data/lib/dependabot/npm_and_yarn/file_updater/npmrc_builder.rb +3 -1
- data/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb +2 -1
- data/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb +4 -1
- data/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb +12 -3
- data/lib/dependabot/npm_and_yarn/file_updater.rb +23 -6
- data/lib/dependabot/npm_and_yarn/helpers.rb +34 -2
- data/lib/dependabot/npm_and_yarn/package_name.rb +24 -7
- data/lib/dependabot/npm_and_yarn/registry_parser.rb +23 -11
- data/lib/dependabot/npm_and_yarn/sub_dependency_files_filterer.rb +21 -4
- data/lib/dependabot/npm_and_yarn/update_checker/conflicting_dependency_resolver.rb +2 -1
- data/lib/dependabot/npm_and_yarn/update_checker/dependency_files_builder.rb +3 -1
- data/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb +5 -2
- data/lib/dependabot/npm_and_yarn/update_checker/library_detector.rb +3 -1
- data/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb +5 -1
- data/lib/dependabot/npm_and_yarn/update_checker/requirements_updater.rb +4 -2
- data/lib/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver.rb +6 -2
- data/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +6 -2
- data/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb +2 -1
- data/lib/dependabot/npm_and_yarn/version.rb +4 -2
- metadata +5 -5
@@ -1,22 +1,27 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "dependabot/dependency_file"
|
5
5
|
require "dependabot/npm_and_yarn/file_parser"
|
6
6
|
require "dependabot/npm_and_yarn/helpers"
|
7
|
+
require "sorbet-runtime"
|
7
8
|
|
8
9
|
module Dependabot
|
9
10
|
module NpmAndYarn
|
10
11
|
class FileParser < Dependabot::FileParsers::Base
|
11
12
|
class LockfileParser
|
13
|
+
extend T::Sig
|
14
|
+
|
12
15
|
require "dependabot/npm_and_yarn/file_parser/yarn_lock"
|
13
16
|
require "dependabot/npm_and_yarn/file_parser/pnpm_lock"
|
14
17
|
require "dependabot/npm_and_yarn/file_parser/json_lock"
|
15
18
|
|
19
|
+
sig { params(dependency_files: T::Array[DependencyFile]).void }
|
16
20
|
def initialize(dependency_files:)
|
17
21
|
@dependency_files = dependency_files
|
18
22
|
end
|
19
23
|
|
24
|
+
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
20
25
|
def parse_set
|
21
26
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
22
27
|
|
@@ -31,24 +36,32 @@ module Dependabot
|
|
31
36
|
dependency_set
|
32
37
|
end
|
33
38
|
|
39
|
+
sig { returns(T::Array[Dependency]) }
|
34
40
|
def parse
|
35
41
|
Helpers.dependencies_with_all_versions_metadata(parse_set)
|
36
42
|
end
|
37
43
|
|
44
|
+
sig do
|
45
|
+
params(dependency_name: String, requirement: T.nilable(String), manifest_name: String)
|
46
|
+
.returns(T.nilable(T::Hash[String, T.untyped]))
|
47
|
+
end
|
38
48
|
def lockfile_details(dependency_name:, requirement:, manifest_name:)
|
49
|
+
details = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
|
39
50
|
potential_lockfiles_for_manifest(manifest_name).each do |lockfile|
|
40
51
|
details = lockfile_for(lockfile).details(dependency_name, requirement, manifest_name)
|
41
52
|
|
42
|
-
|
53
|
+
break if details
|
43
54
|
end
|
44
55
|
|
45
|
-
|
56
|
+
details
|
46
57
|
end
|
47
58
|
|
48
59
|
private
|
49
60
|
|
61
|
+
sig { returns(T::Array[DependencyFile]) }
|
50
62
|
attr_reader :dependency_files
|
51
63
|
|
64
|
+
sig { params(manifest_filename: String).returns(T::Array[DependencyFile]) }
|
52
65
|
def potential_lockfiles_for_manifest(manifest_filename)
|
53
66
|
dir_name = File.dirname(manifest_filename)
|
54
67
|
possible_lockfile_names =
|
@@ -61,12 +74,9 @@ module Dependabot
|
|
61
74
|
.filter_map { |nm| dependency_files.find { |f| f.name == nm } }
|
62
75
|
end
|
63
76
|
|
64
|
-
|
65
|
-
lockfile_for(file).parsed
|
66
|
-
end
|
67
|
-
|
77
|
+
sig { params(file: DependencyFile).returns(T.any(JsonLock, YarnLock, PnpmLock)) }
|
68
78
|
def lockfile_for(file)
|
69
|
-
@lockfiles ||= {}
|
79
|
+
@lockfiles ||= T.let({}, T.nilable(T::Hash[String, T.any(JsonLock, YarnLock, PnpmLock)]))
|
70
80
|
@lockfiles[file.name] ||= if [*package_locks, *shrinkwraps].include?(file)
|
71
81
|
JsonLock.new(file)
|
72
82
|
elsif yarn_locks.include?(file)
|
@@ -76,30 +86,39 @@ module Dependabot
|
|
76
86
|
end
|
77
87
|
end
|
78
88
|
|
89
|
+
sig { returns(T::Array[DependencyFile]) }
|
79
90
|
def package_locks
|
80
|
-
@package_locks ||=
|
91
|
+
@package_locks ||= T.let(
|
81
92
|
dependency_files
|
82
|
-
.select { |f| f.name.end_with?("package-lock.json") }
|
93
|
+
.select { |f| f.name.end_with?("package-lock.json") }, T.nilable(T::Array[DependencyFile])
|
94
|
+
)
|
83
95
|
end
|
84
96
|
|
97
|
+
sig { returns(T::Array[DependencyFile]) }
|
85
98
|
def pnpm_locks
|
86
|
-
@pnpm_locks ||=
|
99
|
+
@pnpm_locks ||= T.let(
|
87
100
|
dependency_files
|
88
|
-
.select { |f| f.name.end_with?("pnpm-lock.yaml") }
|
101
|
+
.select { |f| f.name.end_with?("pnpm-lock.yaml") }, T.nilable(T::Array[DependencyFile])
|
102
|
+
)
|
89
103
|
end
|
90
104
|
|
105
|
+
sig { returns(T::Array[DependencyFile]) }
|
91
106
|
def yarn_locks
|
92
|
-
@yarn_locks ||=
|
107
|
+
@yarn_locks ||= T.let(
|
93
108
|
dependency_files
|
94
|
-
.select { |f| f.name.end_with?("yarn.lock") }
|
109
|
+
.select { |f| f.name.end_with?("yarn.lock") }, T.nilable(T::Array[DependencyFile])
|
110
|
+
)
|
95
111
|
end
|
96
112
|
|
113
|
+
sig { returns(T::Array[DependencyFile]) }
|
97
114
|
def shrinkwraps
|
98
|
-
@shrinkwraps ||=
|
115
|
+
@shrinkwraps ||= T.let(
|
99
116
|
dependency_files
|
100
|
-
.select { |f| f.name.end_with?("npm-shrinkwrap.json") }
|
117
|
+
.select { |f| f.name.end_with?("npm-shrinkwrap.json") }, T.nilable(T::Array[DependencyFile])
|
118
|
+
)
|
101
119
|
end
|
102
120
|
|
121
|
+
sig { returns(T.class_of(Dependabot::NpmAndYarn::Version)) }
|
103
122
|
def version_class
|
104
123
|
NpmAndYarn::Version
|
105
124
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "dependabot/shared_helpers"
|
5
5
|
require "dependabot/errors"
|
6
6
|
require "dependabot/npm_and_yarn/native_helpers"
|
7
|
+
require "sorbet-runtime"
|
7
8
|
|
8
9
|
module Dependabot
|
9
10
|
module NpmAndYarn
|
@@ -44,7 +45,7 @@ module Dependabot
|
|
44
45
|
|
45
46
|
dependency_set << Dependency.new(
|
46
47
|
name: req.split(/(?<=\w)\@/).first,
|
47
|
-
version: version,
|
48
|
+
version: version.to_s,
|
48
49
|
package_manager: "npm_and_yarn",
|
49
50
|
requirements: []
|
50
51
|
)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# See https://docs.npmjs.com/files/package.json for package.json format docs.
|
@@ -15,15 +15,17 @@ require "dependabot/npm_and_yarn/registry_parser"
|
|
15
15
|
require "dependabot/git_metadata_fetcher"
|
16
16
|
require "dependabot/git_commit_checker"
|
17
17
|
require "dependabot/errors"
|
18
|
+
require "sorbet-runtime"
|
18
19
|
|
19
20
|
module Dependabot
|
20
21
|
module NpmAndYarn
|
21
22
|
class FileParser < Dependabot::FileParsers::Base
|
23
|
+
extend T::Sig
|
24
|
+
|
22
25
|
require "dependabot/file_parsers/base/dependency_set"
|
23
26
|
require_relative "file_parser/lockfile_parser"
|
24
27
|
|
25
|
-
DEPENDENCY_TYPES =
|
26
|
-
%w(dependencies devDependencies optionalDependencies).freeze
|
28
|
+
DEPENDENCY_TYPES = T.let(%w(dependencies devDependencies optionalDependencies).freeze, T::Array[String])
|
27
29
|
GIT_URL_REGEX = %r{
|
28
30
|
(?<git_prefix>^|^git.*?|^github:|^bitbucket:|^gitlab:|github\.com/)
|
29
31
|
(?<username>[a-z0-9-]+)/
|
@@ -35,15 +37,23 @@ module Dependabot
|
|
35
37
|
)?$
|
36
38
|
}ix
|
37
39
|
|
38
|
-
|
40
|
+
sig do
|
41
|
+
params(
|
42
|
+
json: T::Hash[String, T.untyped],
|
43
|
+
_block: T.proc.params(arg0: String, arg1: String, arg2: String).void
|
44
|
+
)
|
45
|
+
.void
|
46
|
+
end
|
47
|
+
def self.each_dependency(json, &_block)
|
39
48
|
DEPENDENCY_TYPES.each do |type|
|
40
49
|
deps = json[type] || {}
|
41
50
|
deps.each do |name, requirement|
|
42
|
-
yield
|
51
|
+
yield(name, requirement, type)
|
43
52
|
end
|
44
53
|
end
|
45
54
|
end
|
46
55
|
|
56
|
+
sig { override.returns(T::Array[Dependency]) }
|
47
57
|
def parse
|
48
58
|
dependency_set = DependencySet.new
|
49
59
|
dependency_set += manifest_dependencies
|
@@ -70,11 +80,12 @@ module Dependabot
|
|
70
80
|
|
71
81
|
private
|
72
82
|
|
83
|
+
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
73
84
|
def manifest_dependencies
|
74
85
|
dependency_set = DependencySet.new
|
75
86
|
|
76
87
|
package_files.each do |file|
|
77
|
-
json = JSON.parse(file.content)
|
88
|
+
json = JSON.parse(T.must(file.content))
|
78
89
|
|
79
90
|
# TODO: Currently, Dependabot can't handle flat dependency files
|
80
91
|
# (and will error at the FileUpdater stage, because the
|
@@ -98,16 +109,22 @@ module Dependabot
|
|
98
109
|
dependency_set
|
99
110
|
end
|
100
111
|
|
112
|
+
sig { returns(LockfileParser) }
|
101
113
|
def lockfile_parser
|
102
|
-
@lockfile_parser ||= LockfileParser.new(
|
103
|
-
|
104
|
-
|
114
|
+
@lockfile_parser ||= T.let(LockfileParser.new(
|
115
|
+
dependency_files: dependency_files
|
116
|
+
), T.nilable(Dependabot::NpmAndYarn::FileParser::LockfileParser))
|
105
117
|
end
|
106
118
|
|
119
|
+
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
107
120
|
def lockfile_dependencies
|
108
121
|
lockfile_parser.parse_set
|
109
122
|
end
|
110
123
|
|
124
|
+
sig do
|
125
|
+
params(file: DependencyFile, type: T.untyped, name: String, requirement: String)
|
126
|
+
.returns(T.nilable(Dependency))
|
127
|
+
end
|
111
128
|
def build_dependency(file:, type:, name:, requirement:)
|
112
129
|
lockfile_details = lockfile_parser.lockfile_details(
|
113
130
|
dependency_name: name,
|
@@ -115,6 +132,13 @@ module Dependabot
|
|
115
132
|
manifest_name: file.name
|
116
133
|
)
|
117
134
|
version = version_for(requirement, lockfile_details)
|
135
|
+
converted_version = T.let(if version.nil?
|
136
|
+
nil
|
137
|
+
elsif version.is_a?(String)
|
138
|
+
version
|
139
|
+
else
|
140
|
+
Dependabot::Version.new(version)
|
141
|
+
end, T.nilable(T.any(String, Dependabot::Version)))
|
118
142
|
|
119
143
|
return if lockfile_details && !version
|
120
144
|
return if ignore_requirement?(requirement)
|
@@ -129,7 +153,7 @@ module Dependabot
|
|
129
153
|
|
130
154
|
Dependency.new(
|
131
155
|
name: name,
|
132
|
-
version:
|
156
|
+
version: converted_version,
|
133
157
|
package_manager: "npm_and_yarn",
|
134
158
|
requirements: [{
|
135
159
|
requirement: requirement_for(requirement),
|
@@ -140,10 +164,12 @@ module Dependabot
|
|
140
164
|
)
|
141
165
|
end
|
142
166
|
|
167
|
+
sig { override.void }
|
143
168
|
def check_required_files
|
144
169
|
raise "No package.json!" unless get_original_file("package.json")
|
145
170
|
end
|
146
171
|
|
172
|
+
sig { params(requirement: String).returns(T::Boolean) }
|
147
173
|
def ignore_requirement?(requirement)
|
148
174
|
return true if local_path?(requirement)
|
149
175
|
return true if non_git_url?(requirement)
|
@@ -153,37 +179,49 @@ module Dependabot
|
|
153
179
|
alias_package?(requirement)
|
154
180
|
end
|
155
181
|
|
182
|
+
sig { params(requirement: String).returns(T::Boolean) }
|
156
183
|
def local_path?(requirement)
|
157
184
|
requirement.start_with?("link:", "file:", "/", "./", "../", "~/")
|
158
185
|
end
|
159
186
|
|
187
|
+
sig { params(requirement: String).returns(T::Boolean) }
|
160
188
|
def alias_package?(requirement)
|
161
189
|
requirement.start_with?("npm:")
|
162
190
|
end
|
163
191
|
|
192
|
+
sig { params(requirement: String).returns(T::Boolean) }
|
164
193
|
def non_git_url?(requirement)
|
165
194
|
requirement.include?("://") && !git_url?(requirement)
|
166
195
|
end
|
167
196
|
|
197
|
+
sig { params(requirement: String).returns(T::Boolean) }
|
168
198
|
def git_url?(requirement)
|
169
199
|
requirement.match?(GIT_URL_REGEX)
|
170
200
|
end
|
171
201
|
|
202
|
+
sig { params(requirement: String).returns(T::Boolean) }
|
172
203
|
def git_url_with_semver?(requirement)
|
173
204
|
return false unless git_url?(requirement)
|
174
205
|
|
175
|
-
!requirement.match(GIT_URL_REGEX).named_captures.fetch("semver").nil?
|
206
|
+
!T.must(requirement.match(GIT_URL_REGEX)).named_captures.fetch("semver").nil?
|
176
207
|
end
|
177
208
|
|
209
|
+
sig { params(name: String).returns(T::Boolean) }
|
178
210
|
def aliased_package_name?(name)
|
179
211
|
name.include?("@npm:")
|
180
212
|
end
|
181
213
|
|
214
|
+
sig { returns(T::Array[String]) }
|
182
215
|
def workspace_package_names
|
183
|
-
@workspace_package_names ||=
|
184
|
-
|
216
|
+
@workspace_package_names ||= T.let(package_files.filter_map do |f|
|
217
|
+
JSON.parse(T.must(f.content))["name"]
|
218
|
+
end, T.nilable(T::Array[String]))
|
185
219
|
end
|
186
220
|
|
221
|
+
sig do
|
222
|
+
params(requirement: String, lockfile_details: T.nilable(T::Hash[String, T.untyped]))
|
223
|
+
.returns(T.nilable(T.any(String, Integer, Gem::Version)))
|
224
|
+
end
|
187
225
|
def version_for(requirement, lockfile_details)
|
188
226
|
if git_url_with_semver?(requirement)
|
189
227
|
semver_version = lockfile_version_for(lockfile_details)
|
@@ -203,20 +241,25 @@ module Dependabot
|
|
203
241
|
end
|
204
242
|
end
|
205
243
|
|
244
|
+
sig { params(lockfile_details: T.nilable(T::Hash[String, T.untyped])).returns(T.nilable(String)) }
|
206
245
|
def git_revision_for(lockfile_details)
|
246
|
+
version = T.cast(lockfile_details&.fetch("version", nil), T.nilable(String))
|
247
|
+
resolved = T.cast(lockfile_details&.fetch("resolved", nil), T.nilable(String))
|
207
248
|
[
|
208
|
-
|
209
|
-
|
210
|
-
|
249
|
+
version&.split("#")&.last,
|
250
|
+
resolved&.split("#")&.last,
|
251
|
+
resolved&.split("/")&.last
|
211
252
|
].find { |str| commit_sha?(str) }
|
212
253
|
end
|
213
254
|
|
255
|
+
sig { params(string: T.nilable(String)).returns(T::Boolean) }
|
214
256
|
def commit_sha?(string)
|
215
257
|
return false unless string.is_a?(String)
|
216
258
|
|
217
259
|
string.match?(/^[0-9a-f]{40}$/)
|
218
260
|
end
|
219
261
|
|
262
|
+
sig { params(requirement: String, git_revision: T.nilable(String)).returns(T.nilable(String)) }
|
220
263
|
def version_from_git_revision(requirement, git_revision)
|
221
264
|
tags =
|
222
265
|
Dependabot::GitMetadataFetcher.new(
|
@@ -228,7 +271,7 @@ module Dependabot
|
|
228
271
|
tags.each do |t|
|
229
272
|
next unless t.name.match?(Dependabot::GitCommitChecker::VERSION_REGEX)
|
230
273
|
|
231
|
-
version = t.name.match(Dependabot::GitCommitChecker::VERSION_REGEX)
|
274
|
+
version = T.must(t.name.match(Dependabot::GitCommitChecker::VERSION_REGEX))
|
232
275
|
.named_captures.fetch("version")
|
233
276
|
next unless version_class.correct?(version)
|
234
277
|
|
@@ -240,14 +283,20 @@ module Dependabot
|
|
240
283
|
nil
|
241
284
|
end
|
242
285
|
|
286
|
+
sig do
|
287
|
+
params(lockfile_details: T.nilable(T::Hash[String, T.untyped]))
|
288
|
+
.returns(T.nilable(T.any(String, Integer, Gem::Version)))
|
289
|
+
end
|
243
290
|
def lockfile_version_for(lockfile_details)
|
244
291
|
semver_version_for(lockfile_details&.fetch("version", ""))
|
245
292
|
end
|
246
293
|
|
294
|
+
sig { params(version: String).returns(T.nilable(T.any(String, Integer, Gem::Version))) }
|
247
295
|
def semver_version_for(version)
|
248
296
|
version_class.semver_for(version)
|
249
297
|
end
|
250
298
|
|
299
|
+
sig { params(requirement: String).returns(T.nilable(String)) }
|
251
300
|
def exact_version_for(requirement)
|
252
301
|
req = requirement_class.new(requirement)
|
253
302
|
return unless req.exact?
|
@@ -257,6 +306,10 @@ module Dependabot
|
|
257
306
|
# If it doesn't parse, it's definitely not exact
|
258
307
|
end
|
259
308
|
|
309
|
+
sig do
|
310
|
+
params(name: String, requirement: String, lockfile_details: T.nilable(T::Hash[String, T.untyped]))
|
311
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
312
|
+
end
|
260
313
|
def source_for(name, requirement, lockfile_details)
|
261
314
|
return git_source_for(requirement) if git_url?(requirement)
|
262
315
|
|
@@ -276,22 +329,24 @@ module Dependabot
|
|
276
329
|
).registry_source_for(name)
|
277
330
|
end
|
278
331
|
|
332
|
+
sig { params(requirement: String).returns(T.nilable(String)) }
|
279
333
|
def requirement_for(requirement)
|
280
334
|
return requirement unless git_url?(requirement)
|
281
335
|
|
282
|
-
details = requirement.match(GIT_URL_REGEX).named_captures
|
336
|
+
details = T.must(requirement.match(GIT_URL_REGEX)).named_captures
|
283
337
|
details["semver"]
|
284
338
|
end
|
285
339
|
|
340
|
+
sig { params(requirement: String).returns(T::Hash[Symbol, T.untyped]) }
|
286
341
|
def git_source_for(requirement)
|
287
|
-
details = requirement.match(GIT_URL_REGEX).named_captures
|
288
|
-
prefix = details.fetch("git_prefix")
|
342
|
+
details = T.must(requirement.match(GIT_URL_REGEX)).named_captures
|
343
|
+
prefix = T.must(details.fetch("git_prefix"))
|
289
344
|
|
290
345
|
host = if prefix.include?("git@") || prefix.include?("://")
|
291
|
-
prefix.split("git@").last
|
292
|
-
|
293
|
-
|
294
|
-
|
346
|
+
T.must(prefix.split("git@").last)
|
347
|
+
.sub(%r{.*?://}, "")
|
348
|
+
.sub(%r{[:/]$}, "")
|
349
|
+
.split("#").first
|
295
350
|
elsif prefix.include?("bitbucket") then "bitbucket.org"
|
296
351
|
elsif prefix.include?("gitlab") then "gitlab.com"
|
297
352
|
else
|
@@ -306,29 +361,37 @@ module Dependabot
|
|
306
361
|
}
|
307
362
|
end
|
308
363
|
|
364
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
309
365
|
def support_package_files
|
310
|
-
@support_package_files ||= sub_package_files.select(&:support_file?)
|
366
|
+
@support_package_files ||= T.let(sub_package_files.select(&:support_file?), T.nilable(T::Array[DependencyFile]))
|
311
367
|
end
|
312
368
|
|
369
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
313
370
|
def sub_package_files
|
314
|
-
@sub_package_files
|
315
|
-
|
316
|
-
|
317
|
-
|
371
|
+
return T.must(@sub_package_files) if defined?(@sub_package_files)
|
372
|
+
|
373
|
+
files = dependency_files.select { |f| f.name.end_with?("package.json") }
|
374
|
+
.reject { |f| f.name == "package.json" }
|
375
|
+
.reject { |f| f.name.include?("node_modules/") }
|
376
|
+
@sub_package_files ||= T.let(files, T.nilable(T::Array[Dependabot::DependencyFile]))
|
318
377
|
end
|
319
378
|
|
379
|
+
sig { returns(T::Array[DependencyFile]) }
|
320
380
|
def package_files
|
321
|
-
@package_files ||=
|
381
|
+
@package_files ||= T.let(
|
322
382
|
[
|
323
383
|
dependency_files.find { |f| f.name == "package.json" },
|
324
384
|
*sub_package_files
|
325
|
-
].compact
|
385
|
+
].compact, T.nilable(T::Array[DependencyFile])
|
386
|
+
)
|
326
387
|
end
|
327
388
|
|
389
|
+
sig { returns(T.class_of(Dependabot::NpmAndYarn::Version)) }
|
328
390
|
def version_class
|
329
391
|
NpmAndYarn::Version
|
330
392
|
end
|
331
393
|
|
394
|
+
sig { returns(T.class_of(Dependabot::NpmAndYarn::Requirement)) }
|
332
395
|
def requirement_class
|
333
396
|
NpmAndYarn::Requirement
|
334
397
|
end
|
@@ -33,7 +33,10 @@ module Dependabot
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
attr_reader :lockfile
|
36
|
+
attr_reader :lockfile
|
37
|
+
attr_reader :dependencies
|
38
|
+
attr_reader :dependency_files
|
39
|
+
attr_reader :credentials
|
37
40
|
|
38
41
|
UNREACHABLE_GIT = /fatal: repository '(?<url>.*)' not found/
|
39
42
|
FORBIDDEN_GIT = /fatal: Authentication failed for '(?<url>.*)'/
|
@@ -61,7 +61,9 @@ module Dependabot
|
|
61
61
|
|
62
62
|
private
|
63
63
|
|
64
|
-
attr_reader :dependency_files
|
64
|
+
attr_reader :dependency_files
|
65
|
+
attr_reader :credentials
|
66
|
+
attr_reader :dependencies
|
65
67
|
|
66
68
|
def build_npmrc_content_from_lockfile
|
67
69
|
return unless yarn_lock || package_lock || shrinkwrap
|
@@ -32,7 +32,10 @@ module Dependabot
|
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
attr_reader :dependencies
|
35
|
+
attr_reader :dependencies
|
36
|
+
attr_reader :dependency_files
|
37
|
+
attr_reader :repo_contents_path
|
38
|
+
attr_reader :credentials
|
36
39
|
|
37
40
|
IRRESOLVABLE_PACKAGE = "ERR_PNPM_NO_MATCHING_VERSION"
|
38
41
|
INVALID_REQUIREMENT = "ERR_PNPM_SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER"
|
@@ -39,7 +39,10 @@ module Dependabot
|
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
|
-
attr_reader :dependencies
|
42
|
+
attr_reader :dependencies
|
43
|
+
attr_reader :dependency_files
|
44
|
+
attr_reader :repo_contents_path
|
45
|
+
attr_reader :credentials
|
43
46
|
|
44
47
|
UNREACHABLE_GIT = /ls-remote --tags --heads (?<url>.*)/
|
45
48
|
TIMEOUT_FETCHING_PACKAGE = %r{(?<url>.+)/(?<package>[^/]+): ETIMEDOUT}
|
@@ -342,8 +345,9 @@ module Dependabot
|
|
342
345
|
def write_temporary_dependency_files(yarn_lock, update_package_json: true)
|
343
346
|
write_lockfiles
|
344
347
|
|
345
|
-
if Helpers.yarn_berry?(yarn_lock)
|
346
|
-
|
348
|
+
if Helpers.yarn_berry?(yarn_lock) && yarnrc_yml_file
|
349
|
+
yarnrc_yml_sanitize_content = sanitize_yarnrc_content(yarnrc_yml_content)
|
350
|
+
File.write(".yarnrc.yml", yarnrc_yml_sanitize_content)
|
347
351
|
else
|
348
352
|
File.write(".npmrc", npmrc_content)
|
349
353
|
File.write(".yarnrc", yarnrc_content) if yarnrc_specifies_private_reg?
|
@@ -367,6 +371,11 @@ module Dependabot
|
|
367
371
|
clean_npmrc_in_path(yarn_lock)
|
368
372
|
end
|
369
373
|
|
374
|
+
def sanitize_yarnrc_content(content)
|
375
|
+
# Replace all "${...}" and ${...} occurrences with empty strings
|
376
|
+
content.gsub(/\"\$\{.*?\}\"/, '""').gsub(/\$\{.*?\}/, '""')
|
377
|
+
end
|
378
|
+
|
370
379
|
def clean_npmrc_in_path(yarn_lock)
|
371
380
|
# Berry does not read npmrc files.
|
372
381
|
return if Helpers.yarn_berry?(yarn_lock)
|
@@ -7,10 +7,13 @@ require "dependabot/file_updaters/vendor_updater"
|
|
7
7
|
require "dependabot/file_updaters/artifact_updater"
|
8
8
|
require "dependabot/npm_and_yarn/dependency_files_filterer"
|
9
9
|
require "dependabot/npm_and_yarn/sub_dependency_files_filterer"
|
10
|
+
require "sorbet-runtime"
|
10
11
|
|
11
12
|
module Dependabot
|
12
13
|
module NpmAndYarn
|
13
14
|
class FileUpdater < Dependabot::FileUpdaters::Base
|
15
|
+
extend T::Sig
|
16
|
+
|
14
17
|
require_relative "file_updater/package_json_updater"
|
15
18
|
require_relative "file_updater/npm_lockfile_updater"
|
16
19
|
require_relative "file_updater/yarn_lockfile_updater"
|
@@ -27,6 +30,7 @@ module Dependabot
|
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
33
|
+
sig { override.returns(T::Array[Regexp]) }
|
30
34
|
def self.updated_files_regex
|
31
35
|
[
|
32
36
|
/^package\.json$/,
|
@@ -37,8 +41,9 @@ module Dependabot
|
|
37
41
|
]
|
38
42
|
end
|
39
43
|
|
44
|
+
sig { override.returns(T::Array[DependencyFile]) }
|
40
45
|
def updated_dependency_files
|
41
|
-
updated_files = []
|
46
|
+
updated_files = T.let([], T::Array[DependencyFile])
|
42
47
|
|
43
48
|
updated_files += updated_manifest_files
|
44
49
|
updated_files += updated_lockfiles
|
@@ -68,7 +73,9 @@ module Dependabot
|
|
68
73
|
pnp_updater.updated_files(base_directory: base_dir, only_paths: [".pnp.cjs", ".pnp.data.json"]).each do |file|
|
69
74
|
updated_files << file
|
70
75
|
end
|
71
|
-
vendor_updater.updated_vendor_cache_files(base_directory: base_dir).each
|
76
|
+
T.unsafe(vendor_updater).updated_vendor_cache_files(base_directory: base_dir).each do |file|
|
77
|
+
updated_files << file
|
78
|
+
end
|
72
79
|
install_state_updater.updated_files(base_directory: base_dir).each do |file|
|
73
80
|
updated_files << file
|
74
81
|
end
|
@@ -89,6 +96,7 @@ module Dependabot
|
|
89
96
|
@install_state_path = Helpers.fetch_yarnrc_yml_value("installStatePath", "./.yarn/install-state.gz")
|
90
97
|
end
|
91
98
|
|
99
|
+
sig { returns(Dependabot::FileUpdaters::VendorUpdater) }
|
92
100
|
def vendor_updater
|
93
101
|
Dependabot::FileUpdaters::VendorUpdater.new(
|
94
102
|
repo_contents_path: repo_contents_path,
|
@@ -96,6 +104,7 @@ module Dependabot
|
|
96
104
|
)
|
97
105
|
end
|
98
106
|
|
107
|
+
sig { returns(Dependabot::FileUpdaters::ArtifactUpdater) }
|
99
108
|
def install_state_updater
|
100
109
|
Dependabot::FileUpdaters::ArtifactUpdater.new(
|
101
110
|
repo_contents_path: repo_contents_path,
|
@@ -103,6 +112,7 @@ module Dependabot
|
|
103
112
|
)
|
104
113
|
end
|
105
114
|
|
115
|
+
sig { returns(Dependabot::FileUpdaters::ArtifactUpdater) }
|
106
116
|
def pnp_updater
|
107
117
|
Dependabot::FileUpdaters::ArtifactUpdater.new(
|
108
118
|
repo_contents_path: repo_contents_path,
|
@@ -110,8 +120,9 @@ module Dependabot
|
|
110
120
|
)
|
111
121
|
end
|
112
122
|
|
123
|
+
sig { returns(T::Array[DependencyFile]) }
|
113
124
|
def filtered_dependency_files
|
114
|
-
@filtered_dependency_files ||=
|
125
|
+
@filtered_dependency_files ||= T.let(
|
115
126
|
if dependencies.any?(&:top_level?)
|
116
127
|
DependencyFilesFilterer.new(
|
117
128
|
dependency_files: dependency_files,
|
@@ -122,13 +133,16 @@ module Dependabot
|
|
122
133
|
dependency_files: dependency_files,
|
123
134
|
updated_dependencies: dependencies
|
124
135
|
).files_requiring_update
|
125
|
-
end
|
136
|
+
end, T.nilable(T::Array[DependencyFile])
|
137
|
+
)
|
126
138
|
end
|
127
139
|
|
140
|
+
sig { override.void }
|
128
141
|
def check_required_files
|
129
142
|
raise "No package.json!" unless get_original_file("package.json")
|
130
143
|
end
|
131
144
|
|
145
|
+
sig { params(updated_files: T::Array[DependencyFile]).returns(T::Hash[Symbol, T.untyped]) }
|
132
146
|
def error_context(updated_files:)
|
133
147
|
{
|
134
148
|
dependencies: dependencies.map(&:to_h),
|
@@ -161,11 +175,13 @@ module Dependabot
|
|
161
175
|
.select { |f| f.name.end_with?("npm-shrinkwrap.json") }
|
162
176
|
end
|
163
177
|
|
178
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
164
179
|
def package_files
|
165
|
-
@package_files ||=
|
180
|
+
@package_files ||= T.let(
|
166
181
|
filtered_dependency_files.select do |f|
|
167
182
|
f.name.end_with?("package.json")
|
168
|
-
end
|
183
|
+
end, T.nilable(T::Array[DependencyFile])
|
184
|
+
)
|
169
185
|
end
|
170
186
|
|
171
187
|
def yarn_lock_changed?(yarn_lock)
|
@@ -184,6 +200,7 @@ module Dependabot
|
|
184
200
|
shrinkwrap.content != updated_lockfile_content(shrinkwrap)
|
185
201
|
end
|
186
202
|
|
203
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
187
204
|
def updated_manifest_files
|
188
205
|
package_files.filter_map do |file|
|
189
206
|
updated_content = updated_package_json_content(file)
|