dependabot-npm_and_yarn 0.253.0 → 0.255.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ const {
2
+ parseLockfile,
3
+ } = require("../../lib/pnpm");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const path = require("path");
7
+
8
+ describe("generates an updated pnpm lock for the original file", () => {
9
+
10
+ let tempDir;
11
+ beforeEach(() => {
12
+ tempDir = fs.mkdtempSync(os.tmpdir() + path.sep);
13
+ });
14
+ afterEach(() => fs.rm(tempDir, { recursive: true }, () => {}));
15
+
16
+ function copyDependencies(sourceDir, destDir) {
17
+ const srcPnpmYaml = path.join(
18
+ __dirname,
19
+ `fixtures/parser/${sourceDir}/pnpm-lock.yaml`
20
+ );
21
+ fs.copyFileSync(srcPnpmYaml, `${destDir}/pnpm-lock.yaml`);
22
+ }
23
+
24
+ it("that contains duplicate dependencies", async () =>{
25
+ copyDependencies("no_lockfile_change", tempDir);
26
+ const result = await parseLockfile(tempDir);
27
+
28
+ expect(result.length).toEqual(398);
29
+ })
30
+
31
+ it("that contains only dev dependencies but no (prod) dependencies", async () =>{
32
+ copyDependencies("only_dev_dependencies", tempDir);
33
+ const result = await parseLockfile(tempDir);
34
+
35
+ expect(result).toEqual([
36
+ {
37
+ name: 'etag',
38
+ version: '1.8.0',
39
+ resolved: undefined,
40
+ dev: true,
41
+ specifiers: [ '^1.0.0' ],
42
+ aliased: false
43
+ }
44
+ ]);
45
+ })
46
+
47
+ it("that contains dependencies which locked to versions with peer disambiguation suffix", async () =>{
48
+ copyDependencies("peer_disambiguation", tempDir);
49
+ const result = await parseLockfile(tempDir);
50
+
51
+ expect(result.length).toEqual(122);
52
+ })
53
+
54
+ // Should have the version in the lock file.
55
+ it("that contains dependencies with an empty version", async () =>{
56
+ copyDependencies("empty_version", tempDir);
57
+ const result = await parseLockfile(tempDir);
58
+
59
+ expect(result.length).toEqual(9);
60
+ })
61
+
62
+ })
@@ -48,16 +48,17 @@ d@1, d@^1.0.1:
48
48
  es5-ext "^0.10.50"
49
49
  type "^1.0.1"
50
50
 
51
- es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
52
- version "0.10.53"
53
- resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
54
- integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
51
+ es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
52
+ version "0.10.63"
53
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
54
+ integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
55
55
  dependencies:
56
- es6-iterator "~2.0.3"
57
- es6-symbol "~3.1.3"
58
- next-tick "~1.0.0"
56
+ es6-iterator "^2.0.3"
57
+ es6-symbol "^3.1.3"
58
+ esniff "^2.0.1"
59
+ next-tick "^1.1.0"
59
60
 
60
- es6-iterator@^2.0.3, es6-iterator@~2.0.3:
61
+ es6-iterator@^2.0.3:
61
62
  version "2.0.3"
62
63
  resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
63
64
  integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
@@ -66,7 +67,7 @@ es6-iterator@^2.0.3, es6-iterator@~2.0.3:
66
67
  es5-ext "^0.10.35"
67
68
  es6-symbol "^3.1.1"
68
69
 
69
- es6-symbol@^3.1.1, es6-symbol@~3.1.3:
70
+ es6-symbol@^3.1.1, es6-symbol@^3.1.3:
70
71
  version "3.1.3"
71
72
  resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
72
73
  integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
@@ -84,6 +85,16 @@ es6-weak-map@^2.0.2:
84
85
  es6-iterator "^2.0.3"
85
86
  es6-symbol "^3.1.1"
86
87
 
88
+ esniff@^2.0.1:
89
+ version "2.0.1"
90
+ resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
91
+ integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
92
+ dependencies:
93
+ d "^1.0.1"
94
+ es5-ext "^0.10.62"
95
+ event-emitter "^0.3.5"
96
+ type "^2.7.2"
97
+
87
98
  event-emitter@^0.3.5:
88
99
  version "0.3.5"
89
100
  resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
@@ -135,16 +146,11 @@ memoizee@^0.4.14:
135
146
  next-tick "1"
136
147
  timers-ext "^0.1.5"
137
148
 
138
- next-tick@1:
149
+ next-tick@1, next-tick@^1.1.0:
139
150
  version "1.1.0"
140
151
  resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
141
152
  integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
142
153
 
143
- next-tick@~1.0.0:
144
- version "1.0.0"
145
- resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
146
- integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
147
-
148
154
  objnest@^5.0.6:
149
155
  version "5.0.10"
150
156
  resolved "https://registry.npmjs.org/objnest/-/objnest-5.0.10.tgz#90e43b11870502fcb445e97fcf402499f5f75c75"
@@ -170,3 +176,8 @@ type@^2.0.0:
170
176
  version "2.1.0"
171
177
  resolved "https://registry.npmjs.org/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f"
172
178
  integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==
179
+
180
+ type@^2.7.2:
181
+ version "2.7.2"
182
+ resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
183
+ integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "@colend-contract-helpers",
3
+ "dependencies": {
4
+ "@commitlint/cli": "^15.0.0",
5
+ "is-positive": "^3.1.0",
6
+ "left-pad": "^1.1.3"
7
+ }
8
+ }
@@ -0,0 +1,14 @@
1
+ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2
+ # yarn lockfile v1
3
+
4
+ "@commitlint/cli@^15.0.0":
5
+ version "15.0.0"
6
+ resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-15.0.0.tgz#8e78e86ee2b6955c1a5d140e734a6c171ce367ee"
7
+
8
+ "is-positive@^3.1.0":
9
+ version "3.1.0"
10
+ resolved "https://registry.yarnpkg.com/is-positive/-/is-positive-3.1.0.tgz#857db584a1ba5d1cb2980527fc3b6c435d37b0fd"
11
+
12
+ "left-pad@^1.0.0":
13
+ version "1.0.0"
14
+ resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.0.0.tgz#c84e2417581bbb8eaf2b9e3d7a122e572ab1af37"
@@ -85,4 +85,33 @@ describe("updater", () => {
85
85
  expect(error).not.toBeNull();
86
86
  }
87
87
  });
88
+
89
+ it("with a package.json which contains illegal character '@' in the name", async () => {
90
+ copyDependencies("illegal_character", tempDir);
91
+
92
+ try {
93
+ await updateDependencyFiles(tempDir, [
94
+ {
95
+ name: "@commitlint/cli",
96
+ version: "19.3.0",
97
+ requirements: [
98
+ {
99
+ requirement: "^19.3.0",
100
+ file: "package.json",
101
+ groups: ["devDependencies"],
102
+ source:
103
+ {
104
+ type: "registry",
105
+ url: "https://registry.yarnpkg.com"
106
+ }
107
+ }
108
+ ]
109
+ }
110
+ ]
111
+ );
112
+ } catch (error) {
113
+ expect(error).not.toBeNull();
114
+ expect(error.message).toEqual("package.json: Name contains illegal characters")
115
+ }
116
+ });
88
117
  });
@@ -291,7 +291,7 @@ module Dependabot
291
291
  semver_version_for(lockfile_details&.fetch("version", ""))
292
292
  end
293
293
 
294
- sig { params(version: String).returns(T.nilable(T.any(String, Integer, Gem::Version))) }
294
+ sig { params(version: T.nilable(String)).returns(T.nilable(T.any(String, Integer, Gem::Version))) }
295
295
  def semver_version_for(version)
296
296
  version_class.semver_for(version)
297
297
  end
@@ -1,6 +1,8 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  require "dependabot/npm_and_yarn/file_updater"
5
7
 
6
8
  module Dependabot
@@ -10,13 +12,25 @@ module Dependabot
10
12
  # committed .npmrc
11
13
  # We should refactor this to use UpdateChecker::RegistryFinder
12
14
  class NpmrcBuilder
13
- CENTRAL_REGISTRIES = %w(
14
- registry.npmjs.org
15
- registry.yarnpkg.com
16
- ).freeze
15
+ extend T::Sig
16
+
17
+ CENTRAL_REGISTRIES = T.let(
18
+ %w(
19
+ registry.npmjs.org
20
+ registry.yarnpkg.com
21
+ ).freeze,
22
+ T::Array[String]
23
+ )
17
24
 
18
25
  SCOPED_REGISTRY = /^\s*@(?<scope>\S+):registry\s*=\s*(?<registry>\S+)/
19
26
 
27
+ sig do
28
+ params(
29
+ dependency_files: T::Array[Dependabot::DependencyFile],
30
+ credentials: T::Array[Dependabot::Credential],
31
+ dependencies: T::Array[Dependabot::Dependency]
32
+ ).void
33
+ end
20
34
  def initialize(dependency_files:, credentials:, dependencies: [])
21
35
  @dependency_files = dependency_files
22
36
  @credentials = credentials
@@ -24,6 +38,7 @@ module Dependabot
24
38
  end
25
39
 
26
40
  # PROXY WORK
41
+ sig { returns(String) }
27
42
  def npmrc_content
28
43
  initial_content =
29
44
  if npmrc_file then complete_npmrc_from_credentials
@@ -48,6 +63,7 @@ module Dependabot
48
63
  # PROXY WORK
49
64
  # Yarn allows registries to be defined either in an .npmrc or .yarnrc
50
65
  # so we need to parse both files for registry keys
66
+ sig { returns(String) }
51
67
  def yarnrc_content
52
68
  initial_content =
53
69
  if npmrc_file then complete_yarnrc_from_credentials
@@ -61,65 +77,83 @@ module Dependabot
61
77
 
62
78
  private
63
79
 
80
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
64
81
  attr_reader :dependency_files
82
+
83
+ sig { returns(T::Array[Dependabot::Credential]) }
65
84
  attr_reader :credentials
85
+
86
+ sig { returns(T::Array[Dependabot::Dependency]) }
66
87
  attr_reader :dependencies
67
88
 
89
+ sig { returns(T.nilable(String)) }
68
90
  def build_npmrc_content_from_lockfile
69
91
  return unless yarn_lock || package_lock || shrinkwrap
70
92
  return unless global_registry
71
93
 
72
- registry = global_registry["registry"]
73
- registry = "https://#{registry}" unless registry.start_with?("http")
94
+ registry = T.must(global_registry)["registry"]
95
+ registry = "https://#{registry}" unless registry&.start_with?("http")
74
96
  "registry = #{registry}\n" \
75
97
  "#{npmrc_global_registry_auth_line}" \
76
98
  "always-auth = true"
77
99
  end
78
100
 
101
+ sig { returns(T.nilable(String)) }
79
102
  def build_yarnrc_content_from_lockfile
80
103
  return unless yarn_lock || package_lock
81
104
  return unless global_registry
82
105
 
83
- "registry \"https://#{global_registry['registry']}\"\n" \
106
+ "registry \"https://#{T.must(global_registry)['registry']}\"\n" \
84
107
  "#{yarnrc_global_registry_auth_line}" \
85
108
  "npmAlwaysAuth: true"
86
109
  end
87
110
 
88
- def global_registry # rubocop:disable Metrics/PerceivedComplexity
111
+ # rubocop:disable Metrics/PerceivedComplexity
112
+ # rubocop:disable Metrics/CyclomaticComplexity
113
+ # rubocop:disable Metrics/AbcSize
114
+ sig { returns(T.nilable(Dependabot::Credential)) }
115
+ def global_registry
89
116
  return @global_registry if defined?(@global_registry)
90
117
 
91
- @global_registry =
118
+ @global_registry = T.let(
92
119
  registry_credentials.find do |cred|
93
120
  next false if CENTRAL_REGISTRIES.include?(cred["registry"])
94
121
 
95
122
  # If all the URLs include this registry, it's global
96
- next true if dependency_urls.size.positive? && dependency_urls.all? do |url|
97
- url.include?(cred["registry"])
123
+ next true if dependency_urls&.size&.positive? && dependency_urls&.all? do |url|
124
+ url.include?(T.must(cred["registry"]))
98
125
  end
99
126
 
100
127
  # Check if this registry has already been defined in .npmrc as a scoped registry
101
- next false if npmrc_scoped_registries.any? { |sr| sr.include?(cred["registry"]) }
128
+ next false if npmrc_scoped_registries&.any? { |sr| sr.include?(T.must(cred["registry"])) }
102
129
 
103
- next false if yarnrc_scoped_registries.any? { |sr| sr.include?(cred["registry"]) }
130
+ next false if yarnrc_scoped_registries&.any? { |sr| sr.include?(T.must(cred["registry"])) }
104
131
 
105
132
  # If any unscoped URLs include this registry, assume it's global
106
133
  dependency_urls
107
- .reject { |u| u.include?("@") || u.include?("%40") }
108
- .any? { |url| url.include?(cred["registry"]) }
109
- end
134
+ &.reject { |u| u.include?("@") || u.include?("%40") }
135
+ &.any? { |url| url.include?(T.must(cred["registry"])) }
136
+ end,
137
+ T.nilable(Dependabot::Credential)
138
+ )
110
139
  end
140
+ # rubocop:enable Metrics/PerceivedComplexity
141
+ # rubocop:enable Metrics/CyclomaticComplexity
142
+ # rubocop:enable Metrics/AbcSize
111
143
 
144
+ sig { returns(String) }
112
145
  def npmrc_global_registry_auth_line
113
146
  # This token is passed in from the Dependabot Config
114
147
  # We write it to the .npmrc file so that it can be used by the VulnerabilityAuditor
115
- token = global_registry.fetch("token", nil)
148
+ token = global_registry&.fetch("token", nil)
116
149
  return "" unless token
117
150
 
118
- auth_line(token, global_registry.fetch("registry")) + "\n"
151
+ auth_line(token, global_registry&.fetch("registry")) + "\n"
119
152
  end
120
153
 
154
+ sig { returns(String) }
121
155
  def yarnrc_global_registry_auth_line
122
- token = global_registry.fetch("token", nil)
156
+ token = global_registry&.fetch("token", nil)
123
157
  return "" unless token
124
158
 
125
159
  if token.include?(":")
@@ -133,6 +167,8 @@ module Dependabot
133
167
  end
134
168
  end
135
169
 
170
+ # rubocop:disable Metrics/AbcSize
171
+ sig { returns(T.nilable(T::Array[String])) }
136
172
  def dependency_urls
137
173
  return @dependency_urls if defined?(@dependency_urls)
138
174
 
@@ -154,55 +190,62 @@ module Dependabot
154
190
  npm_lockfile = package_lock || shrinkwrap
155
191
  if npm_lockfile
156
192
  @dependency_urls +=
157
- npm_lockfile.content.scan(/"resolved"\s*:\s*"(.*)"/)
158
- .flatten
159
- .select { |url| url.is_a?(String) }
160
- .reject { |url| url.start_with?("git") }
193
+ T.must(npm_lockfile.content).scan(/"resolved"\s*:\s*"(.*)"/)
194
+ .flatten
195
+ .select { |url| url.is_a?(String) }
196
+ .reject { |url| url.start_with?("git") }
161
197
  end
162
198
  if yarn_lock
163
199
  @dependency_urls +=
164
- yarn_lock.content.scan(/ resolved "(.*?)"/).flatten
200
+ T.must(T.must(yarn_lock).content).scan(/ resolved "(.*?)"/).flatten
165
201
  end
166
202
 
167
203
  # The registry URL for Bintray goes into the lockfile in a
168
204
  # modified format, so we modify it back before checking against
169
205
  # our credentials
170
- @dependency_urls =
206
+ @dependency_urls = T.let(
171
207
  @dependency_urls.map do |url|
172
208
  url.gsub("dl.bintray.com//", "api.bintray.com/npm/")
173
- end
209
+ end,
210
+ T.nilable(T::Array[String])
211
+ )
174
212
  end
213
+ # rubocop:enable Metrics/AbcSize
175
214
 
215
+ sig { returns(String) }
176
216
  def complete_npmrc_from_credentials
177
- initial_content = npmrc_file.content
178
- .gsub(/^.*\$\{.*\}.*/, "").strip + "\n"
217
+ initial_content = T.must(T.must(npmrc_file).content)
218
+ .gsub(/^.*\$\{.*\}.*/, "").strip + "\n"
179
219
  return initial_content unless yarn_lock || package_lock
180
220
  return initial_content unless global_registry
181
221
 
182
- registry = global_registry["registry"]
183
- registry = "https://#{registry}" unless registry.start_with?("http")
222
+ registry = T.must(global_registry)["registry"]
223
+ registry = "https://#{registry}" unless registry&.start_with?("http")
184
224
  initial_content +
185
225
  "registry = #{registry}\n" \
186
226
  "#{npmrc_global_registry_auth_line}" \
187
227
  "always-auth = true\n"
188
228
  end
189
229
 
230
+ sig { returns(String) }
190
231
  def complete_yarnrc_from_credentials
191
- initial_content = yarnrc_file.content
192
- .gsub(/^.*\$\{.*\}.*/, "").strip + "\n"
232
+ initial_content = T.must(T.must(yarnrc_file).content)
233
+ .gsub(/^.*\$\{.*\}.*/, "").strip + "\n"
193
234
  return initial_content unless yarn_lock || package_lock
194
235
  return initial_content unless global_registry
195
236
 
196
237
  initial_content +
197
- "registry: \"https://#{global_registry['registry']}\"\n" \
238
+ "registry: \"https://#{T.must(global_registry)['registry']}\"\n" \
198
239
  "#{yarnrc_global_registry_auth_line}" \
199
240
  "npmAlwaysAuth: true\n"
200
241
  end
201
242
 
243
+ sig { returns(T.nilable(String)) }
202
244
  def build_npmrc_from_yarnrc
203
245
  yarnrc_global_registry =
204
- yarnrc_file.content
205
- .lines.find { |line| line.match?(/^\s*registry\s/) }
246
+ yarnrc_file&.content
247
+ &.lines
248
+ &.find { |line| line.match?(/^\s*registry\s/) }
206
249
  &.match(NpmAndYarn::UpdateChecker::RegistryFinder::YARN_GLOBAL_REGISTRY_REGEX)
207
250
  &.named_captures&.fetch("registry")
208
251
 
@@ -211,10 +254,12 @@ module Dependabot
211
254
  build_npmrc_content_from_lockfile
212
255
  end
213
256
 
257
+ sig { returns(T.nilable(String)) }
214
258
  def build_yarnrc_from_yarnrc
215
259
  yarnrc_global_registry =
216
- yarnrc_file.content
217
- .lines.find { |line| line.match?(/^\s*registry\s/) }
260
+ yarnrc_file&.content
261
+ &.lines
262
+ &.find { |line| line.match?(/^\s*registry\s/) }
218
263
  &.match(/^\s*registry\s+"(?<registry>[^"]+)"/)
219
264
  &.named_captures&.fetch("registry")
220
265
 
@@ -223,12 +268,13 @@ module Dependabot
223
268
  build_yarnrc_content_from_lockfile
224
269
  end
225
270
 
271
+ sig { returns(T::Array[String]) }
226
272
  def credential_lines_for_npmrc
227
- lines = []
273
+ lines = T.let([], T::Array[String])
228
274
  registry_credentials.each do |cred|
229
275
  registry = cred.fetch("registry")
230
276
 
231
- lines += registry_scopes(registry) if registry_scopes(registry)
277
+ lines += T.must(registry_scopes(registry)) if registry_scopes(registry)
232
278
 
233
279
  token = cred.fetch("token", nil)
234
280
  next unless token
@@ -242,6 +288,7 @@ module Dependabot
242
288
  ["always-auth = true"] + lines
243
289
  end
244
290
 
291
+ sig { params(token: String, registry: T.nilable(String)).returns(String) }
245
292
  def auth_line(token, registry = nil)
246
293
  auth = if token.include?(":")
247
294
  encoded_token = Base64.encode64(token).delete("\n")
@@ -262,23 +309,30 @@ module Dependabot
262
309
  "//#{registry_with_trailing_slash}:#{auth}"
263
310
  end
264
311
 
312
+ sig { returns(T.nilable(T::Array[String])) }
265
313
  def npmrc_scoped_registries
266
314
  return [] unless npmrc_file
267
315
 
268
- @npmrc_scoped_registries ||=
269
- npmrc_file.content.lines.select { |line| line.match?(SCOPED_REGISTRY) }
270
- .filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") }
316
+ @npmrc_scoped_registries ||= T.let(
317
+ T.must(T.must(npmrc_file).content).lines.select { |line| line.match?(SCOPED_REGISTRY) }
318
+ .filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") },
319
+ T.nilable(T::Array[String])
320
+ )
271
321
  end
272
322
 
323
+ sig { returns(T.nilable(T::Array[String])) }
273
324
  def yarnrc_scoped_registries
274
325
  return [] unless yarnrc_file
275
326
 
276
- @yarnrc_scoped_registries ||=
277
- yarnrc_file.content.lines.select { |line| line.match?(SCOPED_REGISTRY) }
278
- .filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") }
327
+ @yarnrc_scoped_registries ||= T.let(
328
+ T.must(T.must(yarnrc_file).content).lines.select { |line| line.match?(SCOPED_REGISTRY) }
329
+ .filter_map { |line| line.match(SCOPED_REGISTRY)&.named_captures&.fetch("registry") },
330
+ T.nilable(T::Array[String])
331
+ )
279
332
  end
280
333
 
281
334
  # rubocop:disable Metrics/PerceivedComplexity
335
+ sig { params(registry: String).returns(T.nilable(T::Array[String])) }
282
336
  def registry_scopes(registry)
283
337
  # Central registries don't just apply to scopes
284
338
  return if CENTRAL_REGISTRIES.include?(registry)
@@ -289,13 +343,13 @@ module Dependabot
289
343
  [registry]
290
344
  affected_urls =
291
345
  dependency_urls
292
- .select do |url|
346
+ &.select do |url|
293
347
  next false unless url.include?(registry)
294
348
 
295
349
  other_regs.none? { |r| r.include?(registry) && url.include?(r) }
296
350
  end
297
351
 
298
- scopes = affected_urls.map do |url|
352
+ scopes = T.must(affected_urls).map do |url|
299
353
  url.split(/\%40|@/)[1]&.split(%r{\%2[fF]|/})&.first
300
354
  end.uniq
301
355
 
@@ -306,41 +360,65 @@ module Dependabot
306
360
  end
307
361
  # rubocop:enable Metrics/PerceivedComplexity
308
362
 
363
+ sig { returns(T::Array[Dependabot::Credential]) }
309
364
  def registry_credentials
310
365
  credentials.select { |cred| cred.fetch("type") == "npm_registry" }
311
366
  end
312
367
 
368
+ sig { returns(T.nilable(T::Hash[String, T.untyped])) }
313
369
  def parsed_package_lock
314
- @parsed_package_lock ||= JSON.parse(package_lock.content)
370
+ @parsed_package_lock ||= T.let(
371
+ JSON.parse(T.must(T.must(package_lock).content)),
372
+ T.nilable(T::Hash[String, T.untyped])
373
+ )
315
374
  end
316
375
 
376
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
317
377
  def npmrc_file
318
- @npmrc_file ||= dependency_files
319
- .find { |f| f.name.end_with?(".npmrc") }
378
+ @npmrc_file ||= T.let(
379
+ dependency_files.find { |f| f.name.end_with?(".npmrc") },
380
+ T.nilable(Dependabot::DependencyFile)
381
+ )
320
382
  end
321
383
 
384
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
322
385
  def yarnrc_file
323
- @yarnrc_file ||= dependency_files
324
- .find { |f| f.name.end_with?(".yarnrc") }
386
+ @yarnrc_file ||= T.let(
387
+ dependency_files.find { |f| f.name.end_with?(".yarnrc") },
388
+ T.nilable(Dependabot::DependencyFile)
389
+ )
325
390
  end
326
391
 
392
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
327
393
  def yarnrc_yml_file
328
- @yarnrc_yml_file ||= dependency_files
329
- .find { |f| f.name.end_with?(".yarnrc.yml") }
394
+ @yarnrc_yml_file ||= T.let(
395
+ dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") },
396
+ T.nilable(Dependabot::DependencyFile)
397
+ )
330
398
  end
331
399
 
400
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
332
401
  def yarn_lock
333
- @yarn_lock ||= dependency_files.find { |f| f.name == "yarn.lock" }
402
+ @yarn_lock ||= T.let(
403
+ dependency_files.find { |f| f.name == "yarn.lock" },
404
+ T.nilable(Dependabot::DependencyFile)
405
+ )
334
406
  end
335
407
 
408
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
336
409
  def package_lock
337
- @package_lock ||=
338
- dependency_files.find { |f| f.name == "package-lock.json" }
410
+ @package_lock ||= T.let(
411
+ dependency_files.find { |f| f.name == "package-lock.json" },
412
+ T.nilable(Dependabot::DependencyFile)
413
+ )
339
414
  end
340
415
 
416
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
341
417
  def shrinkwrap
342
- @shrinkwrap ||=
343
- dependency_files.find { |f| f.name == "npm-shrinkwrap.json" }
418
+ @shrinkwrap ||= T.let(
419
+ dependency_files.find { |f| f.name == "npm-shrinkwrap.json" },
420
+ T.nilable(Dependabot::DependencyFile)
421
+ )
344
422
  end
345
423
  end
346
424
  end
@@ -128,6 +128,11 @@ module Dependabot
128
128
  end
129
129
  end
130
130
  rescue SharedHelpers::HelperSubprocessFailed => e
131
+ # package.json name cannot contain characters like empty string or @.
132
+ if e.message.include?("Name contains illegal characters")
133
+ raise Dependabot::DependencyFileNotParseable, e.message
134
+ end
135
+
131
136
  names = dependencies.map(&:name)
132
137
  package_missing = names.any? do |name|
133
138
  e.message.include?("find package \"#{name}")