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.
@@ -1,4 +1,4 @@
1
- # typed: false
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 if defined?(@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 = super
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 = nil unless npmrc.nil? && package_lock
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", {}).each do |dependency_name, details|
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 = Dependabot::DependencyFile.new(
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 = nil
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
- return @npm_version if defined?(@npm_version)
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
- return @yarn_version if defined?(@yarn_version)
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
- return @pnpm_version if defined?(@pnpm_version)
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
- parsed_package_json,
189
- lockfiles: { npm: package_lock || shrinkwrap, yarn: yarn_lock, pnpm: pnpm_lock }
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 = fetch_file_if_present("package-lock.json")
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 = fetch_file_if_present("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 = fetch_file_if_present("pnpm-lock.yaml")
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 = fetch_file_if_present("npm-shrinkwrap.json")
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 = fetch_support_file(".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
- &.tap { |f| f.support_file = true }
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 = fetch_support_file(".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
- &.tap { |f| f.support_file = true }
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
- return @yarnrc_yml if defined?(@yarnrc_yml)
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: false
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
- @parsed ||= JSON.parse(@dependency_file.content)
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