dependabot-npm_and_yarn 0.249.0 → 0.251.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 +45 -18
- data/lib/dependabot/npm_and_yarn/file_fetcher/path_dependency_builder.rb +49 -18
- 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.rb +23 -6
- data/lib/dependabot/npm_and_yarn/helpers.rb +25 -2
- data/lib/dependabot/npm_and_yarn/package_name.rb +24 -7
- data/lib/dependabot/npm_and_yarn/registry_parser.rb +21 -10
- data/lib/dependabot/npm_and_yarn/sub_dependency_files_filterer.rb +19 -3
- data/lib/dependabot/npm_and_yarn/version.rb +4 -2
- metadata +5 -5
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "json"
|
@@ -22,28 +22,32 @@ module Dependabot
|
|
22
22
|
|
23
23
|
# Npm always prefixes file paths in the lockfile "version" with "file:"
|
24
24
|
# even when a naked path is used (e.g. "../dep")
|
25
|
-
NPM_PATH_DEPENDENCY_STARTS = %w(file:).freeze
|
25
|
+
NPM_PATH_DEPENDENCY_STARTS = T.let(%w(file:).freeze, [String])
|
26
26
|
# "link:" is only supported by Yarn but is interchangeable with "file:"
|
27
27
|
# when it specifies a path. Only include Yarn "link:"'s that start with a
|
28
28
|
# path and ignore symlinked package names that have been registered with
|
29
29
|
# "yarn link", e.g. "link:react"
|
30
|
-
PATH_DEPENDENCY_STARTS = %w(file: link:. link:/ link:~/ / ./ ../ ~/).freeze
|
30
|
+
PATH_DEPENDENCY_STARTS = T.let(%w(file: link:. link:/ link:~/ / ./ ../ ~/).freeze,
|
31
|
+
[String, String, String, String, String, String, String, String])
|
31
32
|
PATH_DEPENDENCY_CLEAN_REGEX = /^file:|^link:/
|
32
33
|
DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org"
|
33
34
|
|
35
|
+
sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
|
34
36
|
def self.required_files_in?(filenames)
|
35
37
|
filenames.include?("package.json")
|
36
38
|
end
|
37
39
|
|
40
|
+
sig { override.returns(String) }
|
38
41
|
def self.required_files_message
|
39
42
|
"Repo must contain a package.json."
|
40
43
|
end
|
41
44
|
|
42
45
|
# Overridden to pull any yarn data or plugins which may be stored with Git LFS.
|
46
|
+
sig { override.returns(String) }
|
43
47
|
def clone_repo_contents
|
44
|
-
return @git_lfs_cloned_repo_contents_path
|
48
|
+
return @git_lfs_cloned_repo_contents_path unless @git_lfs_cloned_repo_contents_path.nil?
|
45
49
|
|
46
|
-
@git_lfs_cloned_repo_contents_path
|
50
|
+
@git_lfs_cloned_repo_contents_path ||= T.let(super, T.nilable(String))
|
47
51
|
begin
|
48
52
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
49
53
|
Dir.chdir(@git_lfs_cloned_repo_contents_path) do
|
@@ -57,6 +61,7 @@ module Dependabot
|
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
64
|
+
sig { override.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
60
65
|
def ecosystem_versions
|
61
66
|
package_managers = {}
|
62
67
|
|
@@ -72,9 +77,9 @@ module Dependabot
|
|
72
77
|
|
73
78
|
sig { override.returns(T::Array[DependencyFile]) }
|
74
79
|
def fetch_files
|
75
|
-
fetched_files = []
|
80
|
+
fetched_files = T.let([], T::Array[DependencyFile])
|
76
81
|
fetched_files << package_json
|
77
|
-
fetched_files << npmrc if npmrc
|
82
|
+
fetched_files << T.must(npmrc) if npmrc
|
78
83
|
fetched_files += npm_files if npm_version
|
79
84
|
fetched_files += yarn_files if yarn_version
|
80
85
|
fetched_files += pnpm_files if pnpm_version
|
@@ -87,6 +92,7 @@ module Dependabot
|
|
87
92
|
|
88
93
|
private
|
89
94
|
|
95
|
+
sig { returns(T::Array[DependencyFile]) }
|
90
96
|
def npm_files
|
91
97
|
fetched_npm_files = []
|
92
98
|
fetched_npm_files << package_lock if package_lock && !skip_package_lock?
|
@@ -95,6 +101,7 @@ module Dependabot
|
|
95
101
|
fetched_npm_files
|
96
102
|
end
|
97
103
|
|
104
|
+
sig { returns(T::Array[DependencyFile]) }
|
98
105
|
def yarn_files
|
99
106
|
fetched_yarn_files = []
|
100
107
|
fetched_yarn_files << yarn_lock if yarn_lock
|
@@ -103,6 +110,7 @@ module Dependabot
|
|
103
110
|
fetched_yarn_files
|
104
111
|
end
|
105
112
|
|
113
|
+
sig { returns(T::Array[DependencyFile]) }
|
106
114
|
def pnpm_files
|
107
115
|
fetched_pnpm_files = []
|
108
116
|
fetched_pnpm_files << pnpm_lock if pnpm_lock && !skip_pnpm_lock?
|
@@ -111,6 +119,7 @@ module Dependabot
|
|
111
119
|
fetched_pnpm_files
|
112
120
|
end
|
113
121
|
|
122
|
+
sig { returns(T::Array[DependencyFile]) }
|
114
123
|
def lerna_files
|
115
124
|
fetched_lerna_files = []
|
116
125
|
fetched_lerna_files << lerna_json if lerna_json
|
@@ -121,12 +130,16 @@ module Dependabot
|
|
121
130
|
# If every entry in the lockfile uses the same registry, we can infer
|
122
131
|
# that there is a global .npmrc file, so add it here as if it were in the repo.
|
123
132
|
|
133
|
+
# rubocop:disable Metrics/AbcSize
|
134
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
135
|
+
sig { returns(T.nilable(DependencyFile)) }
|
124
136
|
def inferred_npmrc # rubocop:disable Metrics/PerceivedComplexity
|
125
137
|
return @inferred_npmrc if defined?(@inferred_npmrc)
|
126
|
-
return @inferred_npmrc
|
138
|
+
return @inferred_npmrc ||= T.let(nil, T.nilable(DependencyFile)) unless npmrc.nil? && package_lock
|
127
139
|
|
128
140
|
known_registries = []
|
129
|
-
FileParser::JsonLock.new(package_lock).parsed.fetch("dependencies",
|
141
|
+
FileParser::JsonLock.new(T.must(package_lock)).parsed.fetch("dependencies",
|
142
|
+
{}).each do |dependency_name, details|
|
130
143
|
resolved = details.fetch("resolved", DEFAULT_NPM_REGISTRY)
|
131
144
|
|
132
145
|
begin
|
@@ -147,7 +160,7 @@ module Dependabot
|
|
147
160
|
|
148
161
|
index = path.index(dependency_name)
|
149
162
|
if index
|
150
|
-
registry_base_path = path[0...index].delete_suffix("/")
|
163
|
+
registry_base_path = T.must(path[0...index]).delete_suffix("/")
|
151
164
|
known_registry << registry_base_path
|
152
165
|
end
|
153
166
|
|
@@ -156,79 +169,85 @@ module Dependabot
|
|
156
169
|
|
157
170
|
if known_registries.uniq.length == 1 && known_registries.first != DEFAULT_NPM_REGISTRY
|
158
171
|
Dependabot.logger.info("Inferred global NPM registry is: #{known_registries.first}")
|
159
|
-
return @inferred_npmrc
|
172
|
+
return @inferred_npmrc ||= Dependabot::DependencyFile.new(
|
160
173
|
name: ".npmrc",
|
161
174
|
content: "registry=#{known_registries.first}"
|
162
175
|
)
|
163
176
|
end
|
164
177
|
|
165
|
-
@inferred_npmrc
|
178
|
+
@inferred_npmrc ||= nil
|
166
179
|
end
|
180
|
+
# rubocop:enable Metrics/AbcSize
|
181
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
167
182
|
|
183
|
+
sig { returns(T.nilable(T.any(Integer, String))) }
|
168
184
|
def npm_version
|
169
|
-
|
170
|
-
|
171
|
-
@npm_version = package_manager.setup("npm")
|
185
|
+
@npm_version ||= T.let(package_manager.setup("npm"), T.nilable(T.any(Integer, String)))
|
172
186
|
end
|
173
187
|
|
188
|
+
sig { returns(T.nilable(T.any(Integer, String))) }
|
174
189
|
def yarn_version
|
175
|
-
|
176
|
-
|
177
|
-
@yarn_version = package_manager.setup("yarn")
|
190
|
+
@yarn_version ||= T.let(package_manager.setup("yarn"), T.nilable(T.any(Integer, String)))
|
178
191
|
end
|
179
192
|
|
193
|
+
sig { returns(T.nilable(T.any(Integer, String))) }
|
180
194
|
def pnpm_version
|
181
|
-
|
182
|
-
|
183
|
-
@pnpm_version = package_manager.setup("pnpm")
|
195
|
+
@pnpm_version ||= T.let(package_manager.setup("pnpm"), T.nilable(T.any(Integer, String)))
|
184
196
|
end
|
185
197
|
|
198
|
+
sig { returns(PackageManager) }
|
186
199
|
def package_manager
|
187
|
-
@package_manager ||= PackageManager.new(
|
188
|
-
|
189
|
-
|
190
|
-
|
200
|
+
@package_manager ||= T.let(PackageManager.new(
|
201
|
+
parsed_package_json,
|
202
|
+
lockfiles: { npm: package_lock || shrinkwrap, yarn: yarn_lock, pnpm: pnpm_lock }
|
203
|
+
), T.nilable(PackageManager))
|
191
204
|
end
|
192
205
|
|
206
|
+
sig { returns(DependencyFile) }
|
193
207
|
def package_json
|
194
|
-
@package_json ||= fetch_file_from_host("package.json")
|
208
|
+
@package_json ||= T.let(fetch_file_from_host("package.json"), T.nilable(DependencyFile))
|
195
209
|
end
|
196
210
|
|
211
|
+
sig { returns(T.nilable(DependencyFile)) }
|
197
212
|
def package_lock
|
198
213
|
return @package_lock if defined?(@package_lock)
|
199
214
|
|
200
|
-
@package_lock
|
215
|
+
@package_lock ||= T.let(fetch_file_if_present("package-lock.json"), T.nilable(DependencyFile))
|
201
216
|
end
|
202
217
|
|
218
|
+
sig { returns(T.nilable(DependencyFile)) }
|
203
219
|
def yarn_lock
|
204
220
|
return @yarn_lock if defined?(@yarn_lock)
|
205
221
|
|
206
|
-
@yarn_lock
|
222
|
+
@yarn_lock ||= T.let(fetch_file_if_present("yarn.lock"), T.nilable(DependencyFile))
|
207
223
|
end
|
208
224
|
|
225
|
+
sig { returns(T.nilable(DependencyFile)) }
|
209
226
|
def pnpm_lock
|
210
227
|
return @pnpm_lock if defined?(@pnpm_lock)
|
211
228
|
|
212
|
-
@pnpm_lock
|
229
|
+
@pnpm_lock ||= T.let(fetch_file_if_present("pnpm-lock.yaml"), T.nilable(DependencyFile))
|
213
230
|
end
|
214
231
|
|
232
|
+
sig { returns(T.nilable(DependencyFile)) }
|
215
233
|
def shrinkwrap
|
216
234
|
return @shrinkwrap if defined?(@shrinkwrap)
|
217
235
|
|
218
|
-
@shrinkwrap
|
236
|
+
@shrinkwrap ||= T.let(fetch_file_if_present("npm-shrinkwrap.json"), T.nilable(DependencyFile))
|
219
237
|
end
|
220
238
|
|
239
|
+
sig { returns(T.nilable(DependencyFile)) }
|
221
240
|
def npmrc
|
222
241
|
return @npmrc if defined?(@npmrc)
|
223
242
|
|
224
|
-
@npmrc
|
243
|
+
@npmrc ||= T.let(fetch_support_file(".npmrc"), T.nilable(DependencyFile))
|
225
244
|
|
226
245
|
return @npmrc if @npmrc || directory == "/"
|
227
246
|
|
228
247
|
# Loop through parent directories looking for an npmrc
|
229
248
|
(1..directory.split("/").count).each do |i|
|
230
249
|
@npmrc = fetch_file_from_host(("../" * i) + ".npmrc")
|
231
|
-
|
250
|
+
.tap { |f| f.support_file = true }
|
232
251
|
break if @npmrc
|
233
252
|
rescue Dependabot::DependencyFileNotFound
|
234
253
|
# Ignore errors (.npmrc may not be present)
|
@@ -238,17 +257,18 @@ module Dependabot
|
|
238
257
|
@npmrc
|
239
258
|
end
|
240
259
|
|
260
|
+
sig { returns(T.nilable(DependencyFile)) }
|
241
261
|
def yarnrc
|
242
262
|
return @yarnrc if defined?(@yarnrc)
|
243
263
|
|
244
|
-
@yarnrc
|
264
|
+
@yarnrc ||= T.let(fetch_support_file(".yarnrc"), T.nilable(DependencyFile))
|
245
265
|
|
246
266
|
return @yarnrc if @yarnrc || directory == "/"
|
247
267
|
|
248
268
|
# Loop through parent directories looking for an yarnrc
|
249
269
|
(1..directory.split("/").count).each do |i|
|
250
270
|
@yarnrc = fetch_file_from_host(("../" * i) + ".yarnrc")
|
251
|
-
|
271
|
+
.tap { |f| f.support_file = true }
|
252
272
|
break if @yarnrc
|
253
273
|
rescue Dependabot::DependencyFileNotFound
|
254
274
|
# Ignore errors (.yarnrc may not be present)
|
@@ -258,40 +278,45 @@ module Dependabot
|
|
258
278
|
@yarnrc
|
259
279
|
end
|
260
280
|
|
281
|
+
sig { returns(T.nilable(DependencyFile)) }
|
261
282
|
def yarnrc_yml
|
262
|
-
|
263
|
-
|
264
|
-
@yarnrc_yml = fetch_support_file(".yarnrc.yml")
|
283
|
+
@yarnrc_yml ||= T.let(fetch_support_file(".yarnrc.yml"), T.nilable(DependencyFile))
|
265
284
|
end
|
266
285
|
|
286
|
+
sig { returns(T.nilable(DependencyFile)) }
|
267
287
|
def pnpm_workspace_yaml
|
268
288
|
return @pnpm_workspace_yaml if defined?(@pnpm_workspace_yaml)
|
269
289
|
|
270
|
-
@pnpm_workspace_yaml = fetch_support_file("pnpm-workspace.yaml")
|
290
|
+
@pnpm_workspace_yaml = T.let(fetch_support_file("pnpm-workspace.yaml"), T.nilable(DependencyFile))
|
271
291
|
end
|
272
292
|
|
293
|
+
sig { returns(T.nilable(DependencyFile)) }
|
273
294
|
def lerna_json
|
274
295
|
return @lerna_json if defined?(@lerna_json)
|
275
296
|
|
276
|
-
@lerna_json = fetch_support_file("lerna.json")
|
297
|
+
@lerna_json = T.let(fetch_support_file("lerna.json"), T.nilable(DependencyFile))
|
277
298
|
end
|
278
299
|
|
300
|
+
sig { returns(T::Array[DependencyFile]) }
|
279
301
|
def workspace_package_jsons
|
280
|
-
@workspace_package_jsons ||= fetch_workspace_package_jsons
|
302
|
+
@workspace_package_jsons ||= T.let(fetch_workspace_package_jsons, T.nilable(T::Array[DependencyFile]))
|
281
303
|
end
|
282
304
|
|
305
|
+
sig { returns(T::Array[DependencyFile]) }
|
283
306
|
def lerna_packages
|
284
|
-
@lerna_packages ||= fetch_lerna_packages
|
307
|
+
@lerna_packages ||= T.let(fetch_lerna_packages, T.nilable(T::Array[DependencyFile]))
|
285
308
|
end
|
286
309
|
|
310
|
+
sig { returns(T::Array[DependencyFile]) }
|
287
311
|
def pnpm_workspace_package_jsons
|
288
|
-
@pnpm_workspace_package_jsons ||= fetch_pnpm_workspace_package_jsons
|
312
|
+
@pnpm_workspace_package_jsons ||= T.let(fetch_pnpm_workspace_package_jsons, T.nilable(T::Array[DependencyFile]))
|
289
313
|
end
|
290
314
|
|
291
315
|
# rubocop:disable Metrics/PerceivedComplexity
|
316
|
+
sig { params(fetched_files: T::Array[DependencyFile]).returns(T::Array[DependencyFile]) }
|
292
317
|
def path_dependencies(fetched_files)
|
293
|
-
package_json_files = []
|
294
|
-
unfetchable_deps = []
|
318
|
+
package_json_files = T.let([], T::Array[DependencyFile])
|
319
|
+
unfetchable_deps = T.let([], T::Array[[String, String]])
|
295
320
|
|
296
321
|
path_dependency_details(fetched_files).each do |name, path|
|
297
322
|
# This happens with relative paths in the package-lock. Skipping it since it results
|
@@ -328,8 +353,9 @@ module Dependabot
|
|
328
353
|
end
|
329
354
|
# rubocop:enable Metrics/PerceivedComplexity
|
330
355
|
|
356
|
+
sig { params(fetched_files: T::Array[DependencyFile]).returns(T::Array[[String, String]]) }
|
331
357
|
def path_dependency_details(fetched_files)
|
332
|
-
package_json_path_deps = []
|
358
|
+
package_json_path_deps = T.let([], T::Array[[String, String]])
|
333
359
|
|
334
360
|
fetched_files.each do |file|
|
335
361
|
package_json_path_deps +=
|
@@ -352,6 +378,7 @@ module Dependabot
|
|
352
378
|
|
353
379
|
# rubocop:disable Metrics/PerceivedComplexity
|
354
380
|
# rubocop:disable Metrics/AbcSize
|
381
|
+
sig { params(file: DependencyFile).returns(T::Array[[String, String]]) }
|
355
382
|
def path_dependency_details_from_manifest(file)
|
356
383
|
return [] unless file.name.end_with?("package.json")
|
357
384
|
|
@@ -362,7 +389,7 @@ module Dependabot
|
|
362
389
|
path_to_directory = "../" * current_depth
|
363
390
|
|
364
391
|
dep_types = FileParser::DEPENDENCY_TYPES
|
365
|
-
parsed_manifest = JSON.parse(file.content)
|
392
|
+
parsed_manifest = JSON.parse(T.must(file.content))
|
366
393
|
dependency_objects = parsed_manifest.values_at(*dep_types).compact
|
367
394
|
# Fetch yarn "file:" path "resolutions" so the lockfile can be resolved
|
368
395
|
resolution_objects = parsed_manifest.values_at("resolutions").compact
|
@@ -391,6 +418,7 @@ module Dependabot
|
|
391
418
|
# rubocop:enable Metrics/AbcSize
|
392
419
|
# rubocop:enable Metrics/PerceivedComplexity
|
393
420
|
|
421
|
+
sig { params(parsed_lockfile: T.untyped).returns(T::Array[[String, String]]) }
|
394
422
|
def path_dependency_details_from_npm_lockfile(parsed_lockfile)
|
395
423
|
path_starts = NPM_PATH_DEPENDENCY_STARTS
|
396
424
|
parsed_lockfile.fetch("dependencies", []).to_a
|
@@ -402,13 +430,15 @@ module Dependabot
|
|
402
430
|
# Re-write the glob name to the targeted dependency name (which is used
|
403
431
|
# in the lockfile), for example "parent-package/**/sub-dep/target-dep" >
|
404
432
|
# "target-dep"
|
433
|
+
sig { params(path: String, value: String).returns([String, String]) }
|
405
434
|
def convert_dependency_path_to_name(path, value)
|
406
435
|
# Picking the last two parts that might include a scope
|
407
436
|
parts = path.split("/").last(2)
|
408
|
-
parts.shift if parts.count == 2 && !parts.first.start_with?("@")
|
437
|
+
parts.shift if parts.count == 2 && !T.must(parts.first).start_with?("@")
|
409
438
|
[parts.join("/"), value]
|
410
439
|
end
|
411
440
|
|
441
|
+
sig { returns(T::Array[DependencyFile]) }
|
412
442
|
def fetch_workspace_package_jsons
|
413
443
|
return [] unless parsed_package_json["workspaces"]
|
414
444
|
|
@@ -417,6 +447,7 @@ module Dependabot
|
|
417
447
|
end
|
418
448
|
end
|
419
449
|
|
450
|
+
sig { returns(T::Array[DependencyFile]) }
|
420
451
|
def fetch_lerna_packages
|
421
452
|
return [] unless parsed_lerna_json["packages"]
|
422
453
|
|
@@ -425,6 +456,7 @@ module Dependabot
|
|
425
456
|
end.compact
|
426
457
|
end
|
427
458
|
|
459
|
+
sig { returns(T::Array[DependencyFile]) }
|
428
460
|
def fetch_pnpm_workspace_package_jsons
|
429
461
|
return [] unless parsed_pnpm_workspace_yaml["packages"]
|
430
462
|
|
@@ -433,9 +465,10 @@ module Dependabot
|
|
433
465
|
end
|
434
466
|
end
|
435
467
|
|
468
|
+
sig { params(path: String).returns(T::Array[T.nilable(DependencyFile)]) }
|
436
469
|
def fetch_lerna_packages_from_path(path)
|
437
470
|
package_json = fetch_package_json_if_present(path)
|
438
|
-
return unless package_json
|
471
|
+
return [] unless package_json
|
439
472
|
|
440
473
|
[package_json] + [
|
441
474
|
fetch_file_if_present(File.join(path, "package-lock.json")),
|
@@ -444,6 +477,7 @@ module Dependabot
|
|
444
477
|
]
|
445
478
|
end
|
446
479
|
|
480
|
+
sig { params(workspace_object: T.untyped).returns(T::Array[String]) }
|
447
481
|
def workspace_paths(workspace_object)
|
448
482
|
paths_array =
|
449
483
|
if workspace_object.is_a?(Hash)
|
@@ -456,6 +490,7 @@ module Dependabot
|
|
456
490
|
paths_array.flat_map { |path| recursive_find_directories(path) }
|
457
491
|
end
|
458
492
|
|
493
|
+
sig { params(glob: String).returns(T::Array[String]) }
|
459
494
|
def find_directories(glob)
|
460
495
|
return [glob] unless glob.include?("*") || yarn_ignored_glob(glob)
|
461
496
|
|
@@ -474,6 +509,7 @@ module Dependabot
|
|
474
509
|
matching_paths(glob, paths)
|
475
510
|
end
|
476
511
|
|
512
|
+
sig { params(glob: String, paths: T::Array[String]).returns(T::Array[String]) }
|
477
513
|
def matching_paths(glob, paths)
|
478
514
|
ignored_glob = yarn_ignored_glob(glob)
|
479
515
|
glob = glob.gsub(%r{^\./}, "").gsub(/!\(.*?\)/, "*")
|
@@ -485,6 +521,7 @@ module Dependabot
|
|
485
521
|
results.reject { |filename| File.fnmatch?(ignored_glob, filename, File::FNM_PATHNAME) }
|
486
522
|
end
|
487
523
|
|
524
|
+
sig { params(glob: String, prefix: String).returns(T::Array[String]) }
|
488
525
|
def recursive_find_directories(glob, prefix = "")
|
489
526
|
return [prefix + glob] unless glob.include?("*") || yarn_ignored_glob(glob)
|
490
527
|
|
@@ -492,7 +529,7 @@ module Dependabot
|
|
492
529
|
glob_parts = glob.split("/")
|
493
530
|
|
494
531
|
current_glob = glob_parts.first
|
495
|
-
paths = find_directories(prefix + current_glob)
|
532
|
+
paths = find_directories(prefix + T.must(current_glob))
|
496
533
|
next_parts = current_glob == "**" ? glob_parts : glob_parts.drop(1)
|
497
534
|
return paths if next_parts.empty?
|
498
535
|
|
@@ -503,6 +540,7 @@ module Dependabot
|
|
503
540
|
matching_paths(prefix + glob, paths)
|
504
541
|
end
|
505
542
|
|
543
|
+
sig { params(workspace: String).returns(T.nilable(DependencyFile)) }
|
506
544
|
def fetch_package_json_if_present(workspace)
|
507
545
|
file = File.join(workspace, "package.json")
|
508
546
|
|
@@ -516,52 +554,60 @@ module Dependabot
|
|
516
554
|
end
|
517
555
|
|
518
556
|
# The packages/!(not-this-package) syntax is unique to Yarn
|
557
|
+
sig { params(glob: String).returns(T.any(String, FalseClass)) }
|
519
558
|
def yarn_ignored_glob(glob)
|
520
559
|
glob.match?(/!\(.*?\)/) && glob.gsub(/(!\((.*?)\))/, '\2')
|
521
560
|
end
|
522
561
|
|
562
|
+
sig { returns(T.untyped) }
|
523
563
|
def parsed_package_json
|
524
|
-
JSON.parse(package_json.content)
|
564
|
+
JSON.parse(T.must(package_json.content))
|
525
565
|
rescue JSON::ParserError
|
526
566
|
raise Dependabot::DependencyFileNotParseable, package_json.path
|
527
567
|
end
|
528
568
|
|
569
|
+
sig { returns(T.untyped) }
|
529
570
|
def parsed_package_lock
|
530
571
|
return {} unless package_lock
|
531
572
|
|
532
|
-
JSON.parse(package_lock.content)
|
573
|
+
JSON.parse(T.must(T.must(package_lock).content))
|
533
574
|
rescue JSON::ParserError
|
534
575
|
{}
|
535
576
|
end
|
536
577
|
|
578
|
+
sig { returns(T.untyped) }
|
537
579
|
def parsed_shrinkwrap
|
538
580
|
return {} unless shrinkwrap
|
539
581
|
|
540
|
-
JSON.parse(shrinkwrap.content)
|
582
|
+
JSON.parse(T.must(T.must(shrinkwrap).content))
|
541
583
|
rescue JSON::ParserError
|
542
584
|
{}
|
543
585
|
end
|
544
586
|
|
587
|
+
sig { returns(T.untyped) }
|
545
588
|
def parsed_pnpm_workspace_yaml
|
546
589
|
return {} unless pnpm_workspace_yaml
|
547
590
|
|
548
|
-
YAML.safe_load(pnpm_workspace_yaml.content)
|
591
|
+
YAML.safe_load(T.must(T.must(pnpm_workspace_yaml).content))
|
549
592
|
rescue Psych::SyntaxError
|
550
|
-
raise Dependabot::DependencyFileNotParseable, pnpm_workspace_yaml.path
|
593
|
+
raise Dependabot::DependencyFileNotParseable, T.must(pnpm_workspace_yaml).path
|
551
594
|
end
|
552
595
|
|
596
|
+
sig { returns(T::Boolean) }
|
553
597
|
def skip_package_lock?
|
554
598
|
return false unless npmrc
|
555
599
|
|
556
|
-
npmrc.content.match?(/^package-lock\s*=\s*false/)
|
600
|
+
T.must(T.must(npmrc).content).match?(/^package-lock\s*=\s*false/)
|
557
601
|
end
|
558
602
|
|
603
|
+
sig { returns(T::Boolean) }
|
559
604
|
def skip_pnpm_lock?
|
560
605
|
return false unless npmrc
|
561
606
|
|
562
|
-
npmrc.content.match?(/^lockfile\s*=\s*false/)
|
607
|
+
T.must(T.must(npmrc).content).match?(/^lockfile\s*=\s*false/)
|
563
608
|
end
|
564
609
|
|
610
|
+
sig { params(unfetchable_deps: T::Array[[String, String]]).returns(T::Array[DependencyFile]) }
|
565
611
|
def build_unfetchable_deps(unfetchable_deps)
|
566
612
|
return [] unless package_lock || yarn_lock
|
567
613
|
|
@@ -576,12 +622,13 @@ module Dependabot
|
|
576
622
|
end
|
577
623
|
end
|
578
624
|
|
625
|
+
sig { returns(T.untyped) }
|
579
626
|
def parsed_lerna_json
|
580
627
|
return {} unless lerna_json
|
581
628
|
|
582
|
-
JSON.parse(lerna_json.content)
|
629
|
+
JSON.parse(T.must(T.must(lerna_json).content))
|
583
630
|
rescue JSON::ParserError
|
584
|
-
raise Dependabot::DependencyFileNotParseable, lerna_json.path
|
631
|
+
raise Dependabot::DependencyFileNotParseable, T.must(lerna_json).path
|
585
632
|
end
|
586
633
|
end
|
587
634
|
end
|
@@ -1,28 +1,39 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "json"
|
5
5
|
require "dependabot/errors"
|
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 JsonLock
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
sig { params(dependency_file: DependencyFile).void }
|
12
16
|
def initialize(dependency_file)
|
13
17
|
@dependency_file = dependency_file
|
14
18
|
end
|
15
19
|
|
20
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
16
21
|
def parsed
|
17
|
-
|
22
|
+
json_obj = JSON.parse(T.must(@dependency_file.content))
|
23
|
+
@parsed ||= T.let(json_obj, T.untyped)
|
18
24
|
rescue JSON::ParserError
|
19
25
|
raise Dependabot::DependencyFileNotParseable, @dependency_file.path
|
20
26
|
end
|
21
27
|
|
28
|
+
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
22
29
|
def dependencies
|
23
30
|
recursively_fetch_dependencies(parsed)
|
24
31
|
end
|
25
32
|
|
33
|
+
sig do
|
34
|
+
params(dependency_name: String, _requirement: T.untyped, manifest_name: String)
|
35
|
+
.returns(T.nilable(T::Hash[String, T.untyped]))
|
36
|
+
end
|
26
37
|
def details(dependency_name, _requirement, manifest_name)
|
27
38
|
if Helpers.npm8?(@dependency_file)
|
28
39
|
# NOTE: npm 8 sometimes doesn't install workspace dependencies in the
|
@@ -37,6 +48,10 @@ module Dependabot
|
|
37
48
|
|
38
49
|
private
|
39
50
|
|
51
|
+
sig do
|
52
|
+
params(object_with_dependencies: T::Hash[String, T.untyped])
|
53
|
+
.returns(Dependabot::FileParsers::Base::DependencySet)
|
54
|
+
end
|
40
55
|
def recursively_fetch_dependencies(object_with_dependencies)
|
41
56
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
42
57
|
|
@@ -49,6 +64,8 @@ module Dependabot
|
|
49
64
|
version = Version.semver_for(details["version"])
|
50
65
|
next unless version
|
51
66
|
|
67
|
+
version = version.to_s
|
68
|
+
|
52
69
|
dependency_args = {
|
53
70
|
name: name.split("node_modules/").last,
|
54
71
|
version: version,
|
@@ -73,6 +90,7 @@ module Dependabot
|
|
73
90
|
dependency_set
|
74
91
|
end
|
75
92
|
|
93
|
+
sig { params(manifest_name: String, dependency_name: String).returns(String) }
|
76
94
|
def node_modules_path(manifest_name, dependency_name)
|
77
95
|
return "node_modules/#{dependency_name}" if manifest_name == "package.json"
|
78
96
|
|