dependabot-composer 0.397.0 → 0.399.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c875aeabc51932faf7843fbe6d4444bc294d795159d0c782c0d4daf153d11dd
4
- data.tar.gz: 12a8bcbcfcac84a6c9cdf1bff39d85969a8bf542c473823ec37b0eeb91b7bfcf
3
+ metadata.gz: 07e12166ab0d190876866057dd8196ab1effbdf3ac9e13e8634201d9675c9c3f
4
+ data.tar.gz: 0fc9b490113ad41da273feb357c8b08dc9b35526cdd345692501cd1cae7e03fb
5
5
  SHA512:
6
- metadata.gz: 0d703bf16a31c5a7bdf828b61889901ba8d5f429afab240570aee4ba31981f38b2f3927f43721ebeaa7c231113d35c5fff48fd70f55aa2299ce1afc5c4e3bfdf
7
- data.tar.gz: bd19ceff60eb473eb7b0da0400d127c634ebd5d1e5ca20de9a4313ff1f99dc4f4ba24abfa0ec2da29dc41440b227974aab56bf3503beca192cd1c3e092e3c298
6
+ metadata.gz: c9699dd1e74f17cbc50870681f33115a431105f802548c98676060350ea708544be22308edd1a140095877af63abd11a32bd567fe8301c7f53606b1757e04f03
7
+ data.tar.gz: eb7597f863112fafa2ebde80a654fee792b7a1ac9f2a6a92ef2cb4d5300ea046f55f3cebd5c10b80a8e00dd2adb5263fe9df386e1d88b8b2b22701b7591d1ff8
@@ -405,16 +405,16 @@
405
405
  },
406
406
  {
407
407
  "name": "composer/semver",
408
- "version": "3.4.4",
408
+ "version": "3.5.0",
409
409
  "source": {
410
410
  "type": "git",
411
411
  "url": "https://github.com/composer/semver.git",
412
- "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
412
+ "reference": "f7a296f4c4cf8cb8bb83e35d6951a406bb11afa5"
413
413
  },
414
414
  "dist": {
415
415
  "type": "zip",
416
- "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
417
- "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
416
+ "url": "https://api.github.com/repos/composer/semver/zipball/f7a296f4c4cf8cb8bb83e35d6951a406bb11afa5",
417
+ "reference": "f7a296f4c4cf8cb8bb83e35d6951a406bb11afa5",
418
418
  "shasum": ""
419
419
  },
420
420
  "require": {
@@ -456,7 +456,7 @@
456
456
  "homepage": "http://robbast.nl"
457
457
  }
458
458
  ],
459
- "description": "Semver library that offers utilities, version constraint parsing and validation.",
459
+ "description": "Version comparison library that offers utilities, version constraint parsing and validation.",
460
460
  "keywords": [
461
461
  "semantic",
462
462
  "semver",
@@ -466,7 +466,7 @@
466
466
  "support": {
467
467
  "irc": "ircs://irc.libera.chat:6697/composer",
468
468
  "issues": "https://github.com/composer/semver/issues",
469
- "source": "https://github.com/composer/semver/tree/3.4.4"
469
+ "source": "https://github.com/composer/semver/tree/3.5.0"
470
470
  },
471
471
  "funding": [
472
472
  {
@@ -478,7 +478,7 @@
478
478
  "type": "github"
479
479
  }
480
480
  ],
481
- "time": "2025-08-20T19:15:30+00:00"
481
+ "time": "2026-09-24T14:38:51+00:00"
482
482
  },
483
483
  {
484
484
  "name": "composer/spdx-licenses",
@@ -2563,16 +2563,16 @@
2563
2563
  },
2564
2564
  {
2565
2565
  "name": "friendsofphp/php-cs-fixer",
2566
- "version": "v3.95.25",
2566
+ "version": "v3.95.27",
2567
2567
  "source": {
2568
2568
  "type": "git",
2569
2569
  "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
2570
- "reference": "2cdfc1f3daf173d83a1ebb6177949b58c95de6ff"
2570
+ "reference": "1d0c68ee5f37446d8ad5970b82384cd1bb0a3317"
2571
2571
  },
2572
2572
  "dist": {
2573
2573
  "type": "zip",
2574
- "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2cdfc1f3daf173d83a1ebb6177949b58c95de6ff",
2575
- "reference": "2cdfc1f3daf173d83a1ebb6177949b58c95de6ff",
2574
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1d0c68ee5f37446d8ad5970b82384cd1bb0a3317",
2575
+ "reference": "1d0c68ee5f37446d8ad5970b82384cd1bb0a3317",
2576
2576
  "shasum": ""
2577
2577
  },
2578
2578
  "require": {
@@ -2606,15 +2606,15 @@
2606
2606
  "require-dev": {
2607
2607
  "facile-it/paraunit": "^1.3.1 || ^2.11.0",
2608
2608
  "infection/infection": "^0.32.7",
2609
- "justinrainbow/json-schema": "^6.10.0",
2609
+ "justinrainbow/json-schema": "^6.12.0",
2610
2610
  "keradus/cli-executor": "^2.3",
2611
2611
  "php-coveralls/php-coveralls": "^2.9.1",
2612
2612
  "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8",
2613
2613
  "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8",
2614
- "phpunit/phpunit": "^9.6.35 || ^10.5.64 || ^11.5.56 || ^12.5.31 || ^13.0.6",
2615
- "symfony/polyfill-php85": "^1.38",
2616
- "symfony/var-dumper": "^5.4.48 || ^6.4.36 || ^7.4.8 || ^8.1.1",
2617
- "symfony/yaml": "^5.4.53 || ^6.4.41 || ^7.4.13 || ^8.1.1"
2614
+ "phpunit/phpunit": "^9.6.36 || ^10.5.64 || ^11.5.56 || ^12.5.35 || ^13.3.3",
2615
+ "symfony/polyfill-php85": "^1.41",
2616
+ "symfony/var-dumper": "^5.4.48 || ^6.4.45 || ^7.4.18 || ^8.1.7",
2617
+ "symfony/yaml": "^5.4.53 || ^6.4.45 || ^7.4.18 || ^8.1.6"
2618
2618
  },
2619
2619
  "suggest": {
2620
2620
  "ext-dom": "For handling output formats in XML",
@@ -2655,7 +2655,7 @@
2655
2655
  ],
2656
2656
  "support": {
2657
2657
  "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
2658
- "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.25"
2658
+ "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.27"
2659
2659
  },
2660
2660
  "funding": [
2661
2661
  {
@@ -2663,15 +2663,15 @@
2663
2663
  "type": "github"
2664
2664
  }
2665
2665
  ],
2666
- "time": "2026-09-08T11:11:37+00:00"
2666
+ "time": "2026-09-22T09:54:55+00:00"
2667
2667
  },
2668
2668
  {
2669
2669
  "name": "phpstan/phpstan",
2670
- "version": "2.2.14",
2670
+ "version": "2.2.15",
2671
2671
  "dist": {
2672
2672
  "type": "zip",
2673
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9c672e7a8e791dfc3d30e55f683e73fc0b63a3ac",
2674
- "reference": "9c672e7a8e791dfc3d30e55f683e73fc0b63a3ac",
2673
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b158556ffd26825cf615a1c1f72fb5157a2301b7",
2674
+ "reference": "b158556ffd26825cf615a1c1f72fb5157a2301b7",
2675
2675
  "shasum": ""
2676
2676
  },
2677
2677
  "require": {
@@ -2727,7 +2727,7 @@
2727
2727
  "type": "github"
2728
2728
  }
2729
2729
  ],
2730
- "time": "2026-09-12T21:39:33+00:00"
2730
+ "time": "2026-09-23T12:23:07+00:00"
2731
2731
  },
2732
2732
  {
2733
2733
  "name": "psr/event-dispatcher",
@@ -0,0 +1,41 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ module Composer
8
+ module DocumentValueParser
9
+ extend T::Sig
10
+
11
+ ObjectHash = T.type_alias { T::Hash[String, Object] }
12
+
13
+ sig { params(value: Object, context: String).returns(ObjectHash) }
14
+ def self.object_hash(value, context)
15
+ raise TypeError, "#{context} must be an object" unless value.is_a?(Hash)
16
+
17
+ value.to_h do |raw_key, raw_value|
18
+ key = T.cast(raw_key, Object)
19
+ raise TypeError, "#{context} keys must be strings" unless key.is_a?(String)
20
+
21
+ [key, T.cast(raw_value, Object)]
22
+ end
23
+ end
24
+
25
+ sig { params(value: Object, context: String).returns(String) }
26
+ def self.string(value, context)
27
+ return value if value.is_a?(String)
28
+
29
+ raise TypeError, "#{context} must be a string"
30
+ end
31
+
32
+ sig { params(value: Object, context: String).returns(T.nilable(String)) }
33
+ def self.optional_string(value, context)
34
+ return if value.nil?
35
+
36
+ string(value, context)
37
+ end
38
+ end
39
+ private_constant :DocumentValueParser
40
+ end
41
+ end
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "json"
@@ -7,6 +7,7 @@ require "sorbet-runtime"
7
7
  require "dependabot/dependency_file"
8
8
  require "dependabot/composer/file_fetcher"
9
9
  require "dependabot/composer/file_parser"
10
+ require "dependabot/composer/lockfile_document"
10
11
 
11
12
  module Dependabot
12
13
  module Composer
@@ -19,7 +20,7 @@ module Dependabot
19
20
  @path = path
20
21
  @directory = directory
21
22
  @lockfile = lockfile
22
- @parsed_lockfile = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
23
+ @lockfile_document = T.let(nil, T.nilable(LockfileDocument))
23
24
  end
24
25
 
25
26
  sig { returns(T.nilable(DependencyFile)) }
@@ -45,23 +46,20 @@ module Dependabot
45
46
  sig { returns(String) }
46
47
  attr_reader :path
47
48
 
48
- sig { returns(T.untyped) }
49
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
49
50
  attr_reader :lockfile
50
51
 
51
52
  sig { returns(String) }
52
53
  attr_reader :directory
53
54
 
54
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
55
+ sig { returns(T.nilable(LockfileDocument::PackageRecord)) }
55
56
  def details_from_lockfile
56
57
  keys = FileParser::DEPENDENCY_GROUP_KEYS
57
58
  .map { |h| h.fetch(:lockfile) }
58
59
 
59
60
  keys.each do |key|
60
- next unless parsed_lockfile[key]
61
-
62
- parsed_lockfile[key].each do |details|
63
- return details if details.dig("dist", "url") == path
64
- end
61
+ package = lockfile_document&.find_path_package(key, path)
62
+ return package if package
65
63
  end
66
64
 
67
65
  nil
@@ -69,18 +67,16 @@ module Dependabot
69
67
 
70
68
  sig { returns(T.nilable(String)) }
71
69
  def build_path_dep_content
72
- return unless details_from_lockfile
73
-
74
- details_from_lockfile.to_json
70
+ details_from_lockfile&.to_manifest_json
75
71
  end
76
72
 
77
- sig { returns(T::Hash[String, T.untyped]) }
78
- def parsed_lockfile
79
- return {} unless lockfile
73
+ sig { returns(T.nilable(LockfileDocument)) }
74
+ def lockfile_document
75
+ return unless lockfile
80
76
 
81
- @parsed_lockfile ||= T.let(JSON.parse(lockfile.content), T.nilable(T::Hash[String, T.untyped]))
77
+ @lockfile_document ||= LockfileDocument.from_file(T.must(lockfile))
82
78
  rescue JSON::ParserError
83
- {}
79
+ nil
84
80
  end
85
81
  end
86
82
  end
@@ -30,7 +30,7 @@ module Dependabot
30
30
  def ecosystem_versions
31
31
  {
32
32
  package_managers: {
33
- PackageManager::NAME => Helpers.composer_version(parsed_composer_json, parsed_lockfile)
33
+ PackageManager::NAME => Helpers.composer_version(manifest_document, lockfile_document)
34
34
  }
35
35
  }
36
36
  end
@@ -152,31 +152,17 @@ module Dependabot
152
152
 
153
153
  sig { returns(T::Array[String]) }
154
154
  def artifact_sources
155
- sources.select { |details| details["type"] == "artifact" }.map { |details| details["url"] }
155
+ sources.select { |details| details.type == "artifact" }.map(&:url)
156
156
  end
157
157
 
158
158
  sig { returns(T::Array[String]) }
159
159
  def path_sources
160
- sources.select { |details| details["type"] == "path" }.map { |details| details["url"] }
160
+ sources.select { |details| details.type == "path" }.map(&:url)
161
161
  end
162
162
 
163
- sig { returns(T::Array[T::Hash[String, T.untyped]]) }
163
+ sig { returns(T::Array[ManifestDocument::Repository]) }
164
164
  def sources
165
- @sources ||= T.let(
166
- begin
167
- repos = parsed_composer_json.fetch("repositories", [])
168
- if repos.is_a?(Hash) || repos.is_a?(Array)
169
- repos = repos.values if repos.is_a?(Hash)
170
- repos = repos.grep(Hash)
171
-
172
- repos
173
- .select { |details| details["type"] == "path" || details["type"] == "artifact" }
174
- else
175
- []
176
- end
177
- end,
178
- T.nilable(T::Array[T::Hash[String, T.untyped]])
179
- )
165
+ @sources ||= T.let(manifest_document.repositories, T.nilable(T::Array[ManifestDocument::Repository]))
180
166
  end
181
167
 
182
168
  sig { params(unfetchable_deps: T::Array[String]).returns(T::Array[Dependabot::DependencyFile]) }
@@ -212,44 +198,38 @@ module Dependabot
212
198
  end
213
199
  directories
214
200
  rescue Octokit::NotFound, Gitlab::Error::NotFound
215
- lockfile_path_dependency_paths
216
- .select { |p| p.to_s.start_with?(path.gsub(/\*$/, "")) }
201
+ lockfile_path_dependency_paths(prefix: path.gsub(/\*$/, ""))
217
202
  end
218
203
 
219
- sig { returns(T::Array[String]) }
220
- def lockfile_path_dependency_paths
204
+ sig { params(prefix: String).returns(T::Array[String]) }
205
+ def lockfile_path_dependency_paths(prefix:)
221
206
  keys = FileParser::DEPENDENCY_GROUP_KEYS
222
207
  .map { |h| h.fetch(:lockfile) }
223
208
 
224
209
  keys.flat_map do |key|
225
- next [] unless parsed_lockfile[key]
226
-
227
- parsed_lockfile[key]
228
- .select { |details| details.dig("dist", "type") == "path" }
229
- .map { |details| details.dig("dist", "url") }
210
+ lockfile_document.path_packages(key)
211
+ .select { |package| package.dist_url_starts_with?(prefix) }
212
+ .map(&:dist_url)
230
213
  end
231
214
  end
232
215
 
233
- sig { returns(T::Hash[String, T.untyped]) }
234
- def parsed_composer_json
235
- @parsed_composer_json ||= T.let(
236
- JSON.parse(T.must(composer_json.content)),
237
- T.nilable(T::Hash[String, T.untyped])
238
- )
216
+ sig { returns(ManifestDocument) }
217
+ def manifest_document
218
+ @manifest_document ||= T.let(ManifestDocument.from_file(composer_json), T.nilable(ManifestDocument))
239
219
  rescue JSON::ParserError
240
220
  raise Dependabot::DependencyFileNotParseable, composer_json.path
241
221
  end
242
222
 
243
- sig { returns(T::Hash[String, T.untyped]) }
244
- def parsed_lockfile
245
- return {} unless composer_lock
223
+ sig { returns(LockfileDocument) }
224
+ def lockfile_document
225
+ return LockfileDocument.new(data: {}, context: PackageManager::LOCKFILE_FILENAME) unless composer_lock
246
226
 
247
- @parsed_lockfile ||= T.let(
248
- JSON.parse(T.must(T.must(composer_lock).content)),
249
- T.nilable(T::Hash[String, T.untyped])
227
+ @lockfile_document ||= T.let(
228
+ LockfileDocument.from_file(T.must(composer_lock)),
229
+ T.nilable(LockfileDocument)
250
230
  )
251
231
  rescue JSON::ParserError
252
- {}
232
+ LockfileDocument.new(data: {}, context: PackageManager::LOCKFILE_FILENAME)
253
233
  end
254
234
 
255
235
  sig { params(filename: String).returns(Dependabot::DependencyFile) }
@@ -1,9 +1,11 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/composer"
5
5
  require "dependabot/dependency"
6
6
  require "dependabot/composer/version"
7
+ require "dependabot/composer/manifest_document"
8
+ require "dependabot/composer/lockfile_document"
7
9
  require "dependabot/file_parsers"
8
10
  require "dependabot/file_parsers/base"
9
11
  require "dependabot/shared_helpers"
@@ -94,7 +96,7 @@ module Dependabot
94
96
  # Capture PHP requirement from the composer.json
95
97
  sig { returns(T.nilable(Requirement)) }
96
98
  def php_requirement
97
- requirement_string = Helpers.php_constraint(parsed_composer_json)
99
+ requirement_string = Helpers.php_constraint(manifest_document)
98
100
 
99
101
  return nil unless requirement_string
100
102
 
@@ -117,15 +119,15 @@ module Dependabot
117
119
  manifest = keys[:manifest]
118
120
  next unless manifest.is_a?(String)
119
121
 
120
- next unless parsed_composer_json[manifest].is_a?(Hash)
121
-
122
- parsed_composer_json[manifest].each do |name, req|
122
+ manifest_document.requirements(manifest).each do |entry|
123
+ name = entry.name
123
124
  next unless package?(name)
124
125
 
126
+ req = entry.string_requirement
125
127
  local_package_prefix = ["dev-main", "dev-master", "@dev"]
126
128
 
127
129
  # we avoid updating local packages, so we skip them adding to dependency list
128
- if local_package_prefix.include?(req)
130
+ if req && local_package_prefix.include?(req)
129
131
  Dependabot.logger.info("Skipping #{name} with version #{req} as it cannot be updated.")
130
132
  next
131
133
  end
@@ -143,7 +145,7 @@ module Dependabot
143
145
  version&.match?(/^[0-9a-f]{40}$/)
144
146
  end
145
147
 
146
- dependencies << build_manifest_dependency(name, req, keys)
148
+ dependencies << build_manifest_dependency(name, entry.requirement, keys)
147
149
  end
148
150
  end
149
151
 
@@ -180,13 +182,11 @@ module Dependabot
180
182
 
181
183
  DEPENDENCY_GROUP_KEYS.each do |keys|
182
184
  key = keys.fetch(:lockfile)
183
- next unless parsed_lockfile&.[](key).is_a?(Array)
184
-
185
- parsed_lockfile&.[](key)&.each do |details|
186
- name = details["name"]
187
- next unless name.is_a?(String) && package?(name)
185
+ lockfile_document&.packages(key)&.each do |details|
186
+ name = details.name
187
+ next unless name && package?(name)
188
188
 
189
- version = details["version"]&.to_s&.sub(/^v?/, "")
189
+ version = details.version&.sub(/^v?/, "")
190
190
  next unless version.is_a?(String)
191
191
  next unless version.match?(/^\d/) ||
192
192
  version.match?(/^[0-9a-f]{40}$/)
@@ -219,10 +219,10 @@ module Dependabot
219
219
  package = lockfile_details(name: name, type: type)
220
220
  return unless package
221
221
 
222
- version = package.fetch("version")&.to_s&.sub(/^v?/, "")
222
+ version = package.required_version&.sub(/^v?/, "")
223
223
  return version unless version&.start_with?("dev-")
224
224
 
225
- package.dig("source", "reference")
225
+ package.source_reference
226
226
  end
227
227
 
228
228
  sig do
@@ -230,7 +230,7 @@ module Dependabot
230
230
  name: String,
231
231
  type: String,
232
232
  requirement: String
233
- ).returns(T.nilable(T::Hash[Symbol, T.nilable(String)]))
233
+ ).returns(T.nilable(Dependabot::DependencyRequirement::ObjectHash))
234
234
  end
235
235
  def dependency_source(name:, type:, requirement:)
236
236
  return unless lockfile
@@ -238,22 +238,20 @@ module Dependabot
238
238
  package_details = lockfile_details(name: name, type: type)
239
239
  return unless package_details
240
240
 
241
- if package_details["source"].nil? &&
242
- package_details.dig("dist", "type") == "path"
243
- return { type: "path" }
244
- end
241
+ return { type: "path" } if package_details.path_source?
245
242
 
246
243
  git_dependency_details(package_details, requirement)
247
244
  end
248
245
 
249
246
  sig do
250
247
  params(
251
- package_details: T::Hash[String, T.untyped],
248
+ package_details: LockfileDocument::PackageRecord,
252
249
  requirement: String
253
- ).returns(T.nilable(T::Hash[Symbol, T.nilable(String)]))
250
+ ).returns(T.nilable(Dependabot::DependencyRequirement::ObjectHash))
254
251
  end
255
252
  def git_dependency_details(package_details, requirement)
256
- return unless package_details.dig("source", "type") == "git"
253
+ details = package_details.git_source
254
+ return unless details
257
255
 
258
256
  branch =
259
257
  if requirement.start_with?("dev-")
@@ -261,20 +259,19 @@ module Dependabot
261
259
  .sub(/^dev-/, "")
262
260
  .sub(/\s+as\s.*/, "")
263
261
  .split("#").first
264
- elsif package_details.fetch("version")&.to_s&.start_with?("dev-")
265
- package_details.fetch("version")&.to_s&.sub(/^dev-/, "")
262
+ elsif package_details.required_version&.start_with?("dev-")
263
+ package_details.required_version&.sub(/^dev-/, "")
266
264
  end
267
265
 
268
- details = { type: "git", url: package_details.dig("source", "url") }
269
266
  return details unless branch
270
267
 
271
268
  details.merge(branch: branch, ref: nil)
272
269
  end
273
270
 
274
- sig { params(name: String, type: String).returns(T.nilable(T::Hash[String, T.untyped])) }
271
+ sig { params(name: String, type: String).returns(T.nilable(LockfileDocument::PackageRecord)) }
275
272
  def lockfile_details(name:, type:)
276
273
  key = lockfile_key(type)
277
- parsed_lockfile&.fetch(key, [])&.find { |d| d["name"] == name }
274
+ lockfile_document&.find_package(key, name)
278
275
  end
279
276
 
280
277
  sig { params(type: String).returns(String) }
@@ -296,21 +293,21 @@ module Dependabot
296
293
  raise "No #{PackageManager::MANIFEST_FILENAME}!" unless get_original_file(PackageManager::MANIFEST_FILENAME)
297
294
  end
298
295
 
299
- sig { returns(T.nilable(T::Hash[String, T.untyped])) }
300
- def parsed_lockfile # rubocop:disable Metrics/PerceivedComplexity
296
+ sig { returns(T.nilable(LockfileDocument)) }
297
+ def lockfile_document # rubocop:disable Metrics/PerceivedComplexity
301
298
  return unless lockfile
302
299
 
303
300
  content = lockfile&.content
304
301
 
305
302
  raise Dependabot::DependencyFileNotParseable, lockfile&.path || "" if content.nil? || content.strip.empty?
306
303
 
307
- @parsed_lockfile ||= T.let(JSON.parse(content), T.nilable(T::Hash[String, T.untyped]))
304
+ @lockfile_document ||= T.let(LockfileDocument.from_file(T.must(lockfile)), T.nilable(LockfileDocument))
308
305
  rescue JSON::ParserError
309
306
  raise Dependabot::DependencyFileNotParseable, lockfile&.path || ""
310
307
  end
311
308
 
312
- sig { returns(T::Hash[String, T.untyped]) }
313
- def parsed_composer_json
309
+ sig { returns(ManifestDocument) }
310
+ def manifest_document
314
311
  content = composer_json&.content
315
312
 
316
313
  if content.nil? || content.strip.empty?
@@ -318,7 +315,7 @@ module Dependabot
318
315
  composer_json&.path || ""
319
316
  end
320
317
 
321
- @parsed_composer_json ||= T.let(JSON.parse(content), T.nilable(T::Hash[String, T.untyped]))
318
+ @manifest_document ||= T.let(ManifestDocument.from_file(T.must(composer_json)), T.nilable(ManifestDocument))
322
319
  rescue JSON::ParserError
323
320
  raise Dependabot::DependencyFileNotParseable, composer_json&.path || ""
324
321
  end
@@ -342,7 +339,7 @@ module Dependabot
342
339
  sig { returns(String) }
343
340
  def composer_version
344
341
  @composer_version ||= T.let(
345
- Helpers.composer_version(parsed_composer_json, parsed_lockfile),
342
+ Helpers.composer_version(manifest_document, lockfile_document),
346
343
  T.nilable(String)
347
344
  )
348
345
  end
@@ -509,7 +509,10 @@ module Dependabot
509
509
  sig { returns(String) }
510
510
  def composer_version
511
511
  @composer_version ||= T.let(
512
- Helpers.composer_version(parsed_composer_json, parsed_lockfile),
512
+ Helpers.composer_version(
513
+ manifest_document,
514
+ LockfileDocument.new(data: parsed_lockfile, context: lockfile.path)
515
+ ),
513
516
  T.nilable(String)
514
517
  )
515
518
  end
@@ -537,7 +540,7 @@ module Dependabot
537
540
 
538
541
  sig { returns(T::Hash[String, T::Array[String]]) }
539
542
  def initial_platform
540
- platform_php = Helpers.capture_platform_php(parsed_composer_json)
543
+ platform_php = Helpers.capture_platform_php(manifest_document)
541
544
 
542
545
  platform = {}
543
546
  platform[Language::NAME] = [platform_php] if platform_php.is_a?(String) && requirement_valid?(platform_php)
@@ -545,7 +548,7 @@ module Dependabot
545
548
  # NOTE: We *don't* include the require-dev PHP version in our initial
546
549
  # platform. If we fail to resolve with the PHP version specified in
547
550
  # `require` then it will be picked up in a subsequent iteration.
548
- requirement_php = Helpers.php_constraint(parsed_composer_json)
551
+ requirement_php = Helpers.php_constraint(manifest_document)
549
552
  return platform unless requirement_php.is_a?(String)
550
553
  return platform unless requirement_valid?(requirement_php)
551
554
 
@@ -562,6 +565,14 @@ module Dependabot
562
565
  false
563
566
  end
564
567
 
568
+ sig { returns(ManifestDocument) }
569
+ def manifest_document
570
+ @manifest_document ||= T.let(
571
+ ManifestDocument.new(data: parsed_composer_json, context: composer_json.path),
572
+ T.nilable(ManifestDocument)
573
+ )
574
+ end
575
+
565
576
  sig { returns(T::Hash[String, T.untyped]) }
566
577
  def parsed_composer_json
567
578
  @parsed_composer_json ||= T.let(