dependabot-bun 0.296.2 → 0.296.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/.eslintrc +11 -0
  3. data/helpers/README.md +29 -0
  4. data/helpers/build +26 -0
  5. data/helpers/jest.config.js +5 -0
  6. data/helpers/lib/npm/conflicting-dependency-parser.js +78 -0
  7. data/helpers/lib/npm/index.js +9 -0
  8. data/helpers/lib/npm/vulnerability-auditor.js +291 -0
  9. data/helpers/lib/npm6/helpers.js +25 -0
  10. data/helpers/lib/npm6/index.js +9 -0
  11. data/helpers/lib/npm6/peer-dependency-checker.js +111 -0
  12. data/helpers/lib/npm6/remove-dependencies-from-lockfile.js +22 -0
  13. data/helpers/lib/npm6/subdependency-updater.js +78 -0
  14. data/helpers/lib/npm6/updater.js +199 -0
  15. data/helpers/lib/pnpm/index.js +5 -0
  16. data/helpers/lib/pnpm/lockfile-parser.js +82 -0
  17. data/helpers/lib/yarn/conflicting-dependency-parser.js +176 -0
  18. data/helpers/lib/yarn/fix-duplicates.js +80 -0
  19. data/helpers/lib/yarn/helpers.js +54 -0
  20. data/helpers/lib/yarn/index.js +14 -0
  21. data/helpers/lib/yarn/lockfile-parser.js +21 -0
  22. data/helpers/lib/yarn/peer-dependency-checker.js +132 -0
  23. data/helpers/lib/yarn/replace-lockfile-declaration.js +57 -0
  24. data/helpers/lib/yarn/subdependency-updater.js +83 -0
  25. data/helpers/lib/yarn/updater.js +209 -0
  26. data/helpers/package-lock.json +28519 -0
  27. data/helpers/package.json +29 -0
  28. data/helpers/patches/npm++pacote+9.5.12.patch +14 -0
  29. data/helpers/run.js +30 -0
  30. data/helpers/test/npm6/conflicting-dependency-parser.test.js +66 -0
  31. data/helpers/test/npm6/fixtures/conflicting-dependency-parser/deeply-nested/package-lock.json +591 -0
  32. data/helpers/test/npm6/fixtures/conflicting-dependency-parser/deeply-nested/package.json +14 -0
  33. data/helpers/test/npm6/fixtures/conflicting-dependency-parser/nested/package-lock.json +188 -0
  34. data/helpers/test/npm6/fixtures/conflicting-dependency-parser/nested/package.json +14 -0
  35. data/helpers/test/npm6/fixtures/conflicting-dependency-parser/simple/package-lock.json +27 -0
  36. data/helpers/test/npm6/fixtures/conflicting-dependency-parser/simple/package.json +14 -0
  37. data/helpers/test/npm6/fixtures/updater/original/package-lock.json +16 -0
  38. data/helpers/test/npm6/fixtures/updater/original/package.json +9 -0
  39. data/helpers/test/npm6/fixtures/updater/updated/package-lock.json +16 -0
  40. data/helpers/test/npm6/helpers.js +21 -0
  41. data/helpers/test/npm6/updater.test.js +30 -0
  42. data/helpers/test/pnpm/fixtures/parser/empty_version/pnpm-lock.yaml +72 -0
  43. data/helpers/test/pnpm/fixtures/parser/no_lockfile_change/pnpm-lock.yaml +2744 -0
  44. data/helpers/test/pnpm/fixtures/parser/only_dev_dependencies/pnpm-lock.yaml +16 -0
  45. data/helpers/test/pnpm/fixtures/parser/peer_disambiguation/pnpm-lock.yaml +855 -0
  46. data/helpers/test/pnpm/lockfile-parser.test.js +62 -0
  47. data/helpers/test/yarn/conflicting-dependency-parser.test.js +83 -0
  48. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/deeply-nested/package.json +14 -0
  49. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/deeply-nested/yarn.lock +496 -0
  50. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/dev-dependencies/package.json +14 -0
  51. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/dev-dependencies/yarn.lock +21 -0
  52. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/nested/package.json +14 -0
  53. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/nested/yarn.lock +183 -0
  54. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/simple/package.json +14 -0
  55. data/helpers/test/yarn/fixtures/conflicting-dependency-parser/simple/yarn.lock +21 -0
  56. data/helpers/test/yarn/fixtures/updater/illegal_character/package.json +8 -0
  57. data/helpers/test/yarn/fixtures/updater/illegal_character/yarn.lock +14 -0
  58. data/helpers/test/yarn/fixtures/updater/original/package.json +6 -0
  59. data/helpers/test/yarn/fixtures/updater/original/yarn.lock +11 -0
  60. data/helpers/test/yarn/fixtures/updater/updated/yarn.lock +12 -0
  61. data/helpers/test/yarn/fixtures/updater/with-version-comments/package.json +5 -0
  62. data/helpers/test/yarn/fixtures/updater/with-version-comments/yarn.lock +13 -0
  63. data/helpers/test/yarn/helpers.js +18 -0
  64. data/helpers/test/yarn/updater.test.js +117 -0
  65. data/lib/dependabot/bun/bun_package_manager.rb +47 -0
  66. data/lib/dependabot/bun/constraint_helper.rb +359 -0
  67. data/lib/dependabot/bun/dependency_files_filterer.rb +157 -0
  68. data/lib/dependabot/bun/file_fetcher/path_dependency_builder.rb +184 -0
  69. data/lib/dependabot/bun/file_fetcher.rb +402 -0
  70. data/lib/dependabot/bun/file_parser/bun_lock.rb +140 -0
  71. data/lib/dependabot/bun/file_parser/lockfile_parser.rb +105 -0
  72. data/lib/dependabot/bun/file_parser.rb +477 -0
  73. data/lib/dependabot/bun/file_updater/bun_lockfile_updater.rb +144 -0
  74. data/lib/dependabot/bun/file_updater/npmrc_builder.rb +256 -0
  75. data/lib/dependabot/bun/file_updater/package_json_preparer.rb +88 -0
  76. data/lib/dependabot/bun/file_updater/package_json_updater.rb +378 -0
  77. data/lib/dependabot/bun/file_updater.rb +203 -0
  78. data/lib/dependabot/bun/helpers.rb +93 -0
  79. data/lib/dependabot/bun/language.rb +45 -0
  80. data/lib/dependabot/bun/metadata_finder.rb +214 -0
  81. data/lib/dependabot/bun/native_helpers.rb +19 -0
  82. data/lib/dependabot/bun/package_manager.rb +280 -0
  83. data/lib/dependabot/bun/package_name.rb +118 -0
  84. data/lib/dependabot/bun/pnpm_package_manager.rb +55 -0
  85. data/lib/dependabot/bun/registry_helper.rb +188 -0
  86. data/lib/dependabot/bun/registry_parser.rb +93 -0
  87. data/lib/dependabot/bun/requirement.rb +146 -0
  88. data/lib/dependabot/bun/sub_dependency_files_filterer.rb +82 -0
  89. data/lib/dependabot/bun/update_checker/conflicting_dependency_resolver.rb +59 -0
  90. data/lib/dependabot/bun/update_checker/dependency_files_builder.rb +79 -0
  91. data/lib/dependabot/bun/update_checker/latest_version_finder.rb +448 -0
  92. data/lib/dependabot/bun/update_checker/library_detector.rb +76 -0
  93. data/lib/dependabot/bun/update_checker/registry_finder.rb +279 -0
  94. data/lib/dependabot/bun/update_checker/requirements_updater.rb +206 -0
  95. data/lib/dependabot/bun/update_checker/subdependency_version_resolver.rb +154 -0
  96. data/lib/dependabot/bun/update_checker/version_resolver.rb +583 -0
  97. data/lib/dependabot/bun/update_checker/vulnerability_auditor.rb +164 -0
  98. data/lib/dependabot/bun/update_checker.rb +455 -0
  99. data/lib/dependabot/bun/version.rb +138 -0
  100. data/lib/dependabot/bun/version_selector.rb +61 -0
  101. data/lib/dependabot/bun.rb +337 -35
  102. metadata +108 -65
  103. data/lib/dependabot/javascript/bun/file_fetcher.rb +0 -77
  104. data/lib/dependabot/javascript/bun/file_parser/bun_lock.rb +0 -156
  105. data/lib/dependabot/javascript/bun/file_parser/lockfile_parser.rb +0 -55
  106. data/lib/dependabot/javascript/bun/file_parser.rb +0 -74
  107. data/lib/dependabot/javascript/bun/file_updater/lockfile_updater.rb +0 -138
  108. data/lib/dependabot/javascript/bun/file_updater.rb +0 -75
  109. data/lib/dependabot/javascript/bun/helpers.rb +0 -72
  110. data/lib/dependabot/javascript/bun/package_manager.rb +0 -48
  111. data/lib/dependabot/javascript/bun/requirement.rb +0 -11
  112. data/lib/dependabot/javascript/bun/update_checker/conflicting_dependency_resolver.rb +0 -64
  113. data/lib/dependabot/javascript/bun/update_checker/dependency_files_builder.rb +0 -47
  114. data/lib/dependabot/javascript/bun/update_checker/latest_version_finder.rb +0 -450
  115. data/lib/dependabot/javascript/bun/update_checker/library_detector.rb +0 -76
  116. data/lib/dependabot/javascript/bun/update_checker/requirements_updater.rb +0 -203
  117. data/lib/dependabot/javascript/bun/update_checker/subdependency_version_resolver.rb +0 -144
  118. data/lib/dependabot/javascript/bun/update_checker/version_resolver.rb +0 -525
  119. data/lib/dependabot/javascript/bun/update_checker/vulnerability_auditor.rb +0 -165
  120. data/lib/dependabot/javascript/bun/update_checker.rb +0 -440
  121. data/lib/dependabot/javascript/bun/version.rb +0 -11
  122. data/lib/dependabot/javascript/shared/constraint_helper.rb +0 -359
  123. data/lib/dependabot/javascript/shared/dependency_files_filterer.rb +0 -164
  124. data/lib/dependabot/javascript/shared/file_fetcher.rb +0 -283
  125. data/lib/dependabot/javascript/shared/file_parser/lockfile_parser.rb +0 -106
  126. data/lib/dependabot/javascript/shared/file_parser.rb +0 -454
  127. data/lib/dependabot/javascript/shared/file_updater/npmrc_builder.rb +0 -394
  128. data/lib/dependabot/javascript/shared/file_updater/package_json_preparer.rb +0 -87
  129. data/lib/dependabot/javascript/shared/file_updater/package_json_updater.rb +0 -376
  130. data/lib/dependabot/javascript/shared/file_updater.rb +0 -179
  131. data/lib/dependabot/javascript/shared/language.rb +0 -45
  132. data/lib/dependabot/javascript/shared/metadata_finder.rb +0 -209
  133. data/lib/dependabot/javascript/shared/native_helpers.rb +0 -21
  134. data/lib/dependabot/javascript/shared/package_manager_detector.rb +0 -72
  135. data/lib/dependabot/javascript/shared/package_name.rb +0 -118
  136. data/lib/dependabot/javascript/shared/registry_helper.rb +0 -190
  137. data/lib/dependabot/javascript/shared/registry_parser.rb +0 -93
  138. data/lib/dependabot/javascript/shared/requirement.rb +0 -144
  139. data/lib/dependabot/javascript/shared/sub_dependency_files_filterer.rb +0 -79
  140. data/lib/dependabot/javascript/shared/update_checker/dependency_files_builder.rb +0 -87
  141. data/lib/dependabot/javascript/shared/update_checker/registry_finder.rb +0 -358
  142. data/lib/dependabot/javascript/shared/version.rb +0 -133
  143. data/lib/dependabot/javascript/shared/version_selector.rb +0 -60
  144. data/lib/dependabot/javascript.rb +0 -39
@@ -1,359 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Dependabot
5
- module Javascript
6
- module Shared
7
- module ConstraintHelper
8
- extend T::Sig
9
-
10
- # Regex Components for Semantic Versioning
11
- DIGIT = "\\d+" # Matches a single number (e.g., "1")
12
- PRERELEASE = "(?:-[a-zA-Z0-9.-]+)?" # Matches optional pre-release tag (e.g., "-alpha")
13
- BUILD_METADATA = "(?:\\+[a-zA-Z0-9.-]+)?" # Matches optional build metadata (e.g., "+001")
14
-
15
- # Matches semantic versions:
16
- VERSION = T.let("#{DIGIT}(?:\\.#{DIGIT}){0,2}#{PRERELEASE}#{BUILD_METADATA}".freeze, String)
17
-
18
- VERSION_REGEX = T.let(/^#{VERSION}$/, Regexp)
19
-
20
- # Base regex for SemVer (major.minor.patch[-prerelease][+build])
21
- # This pattern extracts valid semantic versioning strings based on the SemVer 2.0 specification.
22
- SEMVER_REGEX = T.let(/
23
- (?<version>\d+\.\d+\.\d+) # Match major.minor.patch (e.g., 1.2.3)
24
- (?:-(?<prerelease>[a-zA-Z0-9.-]+))? # Optional prerelease (e.g., -alpha.1, -rc.1, -beta.5)
25
- (?:\+(?<build>[a-zA-Z0-9.-]+))? # Optional build metadata (e.g., +build.20231101, +exp.sha.5114f85)
26
- /x, Regexp)
27
-
28
- # Full SemVer validation regex (ensures the entire string is a valid SemVer)
29
- # This ensures the entire input strictly follows SemVer, without extra characters before/after.
30
- SEMVER_VALIDATION_REGEX = T.let(/^#{SEMVER_REGEX}$/, Regexp)
31
-
32
- # SemVer constraint regex (supports package.json version constraints)
33
- # This pattern ensures proper parsing of SemVer versions with optional operators.
34
- SEMVER_CONSTRAINT_REGEX = T.let(/
35
- (?: (>=|<=|>|<|=|~|\^)\s*)? # Make operators optional (e.g., >=, ^, ~)
36
- (\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?(?:\+[a-zA-Z0-9.-]+)?) # Match full SemVer versions
37
- | (\*|latest) # Match wildcard (*) or 'latest'
38
- /x, Regexp)
39
-
40
- # /(>=|<=|>|<|=|~|\^)\s*(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?(?:\+[a-zA-Z0-9.-]+)?)|(\*|latest)/
41
-
42
- SEMVER_OPERATOR_REGEX = /^(>=|<=|>|<|~|\^|=)$/
43
-
44
- # Constraint Types as Constants
45
- CARET_CONSTRAINT_REGEX = T.let(/^\^\s*(#{VERSION})$/, Regexp)
46
- TILDE_CONSTRAINT_REGEX = T.let(/^~\s*(#{VERSION})$/, Regexp)
47
- EXACT_CONSTRAINT_REGEX = T.let(/^\s*(#{VERSION})$/, Regexp)
48
- GREATER_THAN_EQUAL_REGEX = T.let(/^>=\s*(#{VERSION})$/, Regexp)
49
- LESS_THAN_EQUAL_REGEX = T.let(/^<=\s*(#{VERSION})$/, Regexp)
50
- GREATER_THAN_REGEX = T.let(/^>\s*(#{VERSION})$/, Regexp)
51
- LESS_THAN_REGEX = T.let(/^<\s*(#{VERSION})$/, Regexp)
52
- WILDCARD_REGEX = T.let(/^\*$/, Regexp)
53
- LATEST_REGEX = T.let(/^latest$/, Regexp)
54
- SEMVER_CONSTANTS = ["*", "latest"].freeze
55
-
56
- # Unified Regex for Valid Constraints
57
- VALID_CONSTRAINT_REGEX = T.let(Regexp.union(
58
- CARET_CONSTRAINT_REGEX,
59
- TILDE_CONSTRAINT_REGEX,
60
- EXACT_CONSTRAINT_REGEX,
61
- GREATER_THAN_EQUAL_REGEX,
62
- LESS_THAN_EQUAL_REGEX,
63
- GREATER_THAN_REGEX,
64
- LESS_THAN_REGEX,
65
- WILDCARD_REGEX,
66
- LATEST_REGEX
67
- ).freeze, Regexp)
68
-
69
- # Extract unique constraints from the given constraint expression.
70
- # @param constraint_expression [T.nilable(String)] The semver constraint expression.
71
- # @return [T::Array[String]] The list of unique Ruby-compatible constraints.
72
- sig do
73
- params(
74
- constraint_expression: T.nilable(String),
75
- dependabot_versions: T.nilable(T::Array[Dependabot::Version])
76
- )
77
- .returns(T.nilable(T::Array[String]))
78
- end
79
- def self.extract_ruby_constraints(constraint_expression, dependabot_versions = nil)
80
- parsed_constraints = parse_constraints(constraint_expression, dependabot_versions)
81
-
82
- return nil unless parsed_constraints
83
-
84
- parsed_constraints.filter_map { |parsed| parsed[:constraint] }
85
- end
86
-
87
- # rubocop:disable Metrics/AbcSize
88
- # rubocop:disable Metrics/CyclomaticComplexity
89
- # rubocop:disable Metrics/MethodLength
90
- # rubocop:disable Metrics/PerceivedComplexity
91
- sig do
92
- params(constraint_expression: T.nilable(String))
93
- .returns(T.nilable(T::Array[String]))
94
- end
95
- def self.split_constraints(constraint_expression)
96
- normalized_constraint = constraint_expression&.strip
97
- return [] if normalized_constraint.nil? || normalized_constraint.empty?
98
-
99
- # Split constraints by logical OR (`||`)
100
- constraint_groups = normalized_constraint.split("||")
101
-
102
- # Split constraints by logical AND (`,`)
103
- constraint_groups = constraint_groups.map do |or_constraint|
104
- or_constraint.split(",").map(&:strip)
105
- end.flatten
106
-
107
- constraint_groups = constraint_groups.map do |constraint|
108
- tokens = constraint.split(/\s+/).map(&:strip)
109
-
110
- and_constraints = []
111
-
112
- previous = T.let(nil, T.nilable(String))
113
- operator = T.let(false, T.nilable(T::Boolean))
114
- wildcard = T.let(false, T::Boolean)
115
-
116
- tokens.each do |token|
117
- token = token.strip
118
- next if token.empty?
119
-
120
- # Invalid constraint if wildcard and anything else
121
- return nil if wildcard
122
-
123
- # If token is one of the operators (>=, <=, >, <, ~, ^, =)
124
- if token.match?(SEMVER_OPERATOR_REGEX)
125
- wildcard = false
126
- operator = true
127
- # If token is wildcard or latest
128
- elsif token.match?(/(\*|latest)/)
129
- and_constraints << token
130
- wildcard = true
131
- operator = false
132
- # If token is exact version (e.g., "1.2.3")
133
- elsif token.match(VERSION_REGEX)
134
- and_constraints << if operator
135
- "#{previous}#{token}"
136
- else
137
- token
138
- end
139
- wildcard = false
140
- operator = false
141
- # If token is a valid constraint (e.g., ">=1.2.3", "<=2.0.0")
142
- elsif token.match(VALID_CONSTRAINT_REGEX)
143
- return nil if operator
144
-
145
- and_constraints << token
146
-
147
- wildcard = false
148
- operator = false
149
- else
150
- # invalid constraint
151
- return nil
152
- end
153
- previous = token
154
- end
155
- and_constraints.uniq
156
- end.flatten
157
- constraint_groups if constraint_groups.any?
158
- end
159
-
160
- # rubocop:enable Metrics/AbcSize
161
- # rubocop:enable Metrics/CyclomaticComplexity
162
- # rubocop:enable Metrics/MethodLength
163
- # rubocop:enable Metrics/PerceivedComplexity
164
-
165
- # Find the highest version from the given constraint expression.
166
- # @param constraint_expression [T.nilable(String)] The semver constraint expression.
167
- # @return [T.nilable(String)] The highest version, or nil if no versions are available.
168
- sig do
169
- params(
170
- constraint_expression: T.nilable(String),
171
- dependabot_versions: T.nilable(T::Array[Dependabot::Version])
172
- )
173
- .returns(T.nilable(String))
174
- end
175
- def self.find_highest_version_from_constraint_expression(constraint_expression, dependabot_versions = nil)
176
- parsed_constraints = parse_constraints(constraint_expression, dependabot_versions)
177
-
178
- return nil unless parsed_constraints
179
-
180
- parsed_constraints
181
- .filter_map { |parsed| parsed[:version] } # Extract all versions
182
- .max_by { |version| Version.new(version) }
183
- end
184
-
185
- # Parse all constraints (split by logical OR `||`) and convert to Ruby-compatible constraints.
186
- # Return:
187
- # - `nil` if the constraint expression is invalid
188
- # - `[]` if the constraint expression is valid but represents "no constraints"
189
- # - An array of hashes for valid constraints with details about the constraint and version
190
- sig do
191
- params(
192
- constraint_expression: T.nilable(String),
193
- dependabot_versions: T.nilable(T::Array[Dependabot::Version])
194
- )
195
- .returns(T.nilable(T::Array[T::Hash[Symbol, T.nilable(String)]]))
196
- end
197
- def self.parse_constraints(constraint_expression, dependabot_versions = nil)
198
- splitted_constraints = split_constraints(constraint_expression)
199
-
200
- return unless splitted_constraints
201
-
202
- constraints = to_ruby_constraints_with_versions(splitted_constraints, dependabot_versions)
203
- constraints
204
- end
205
-
206
- sig do
207
- params(
208
- constraints: T::Array[String],
209
- dependabot_versions: T.nilable(T::Array[Dependabot::Version])
210
- ).returns(T::Array[T::Hash[Symbol, T.nilable(String)]])
211
- end
212
- def self.to_ruby_constraints_with_versions(constraints, dependabot_versions = [])
213
- constraints.filter_map do |constraint|
214
- parsed = to_ruby_constraint_with_version(constraint, dependabot_versions)
215
- parsed if parsed
216
- end.uniq
217
- end
218
-
219
- # rubocop:disable Metrics/MethodLength
220
- # rubocop:disable Metrics/PerceivedComplexity
221
- # rubocop:disable Metrics/AbcSize
222
- # rubocop:disable Metrics/CyclomaticComplexity
223
- # Converts a semver constraint to a Ruby-compatible constraint and extracts the version, if available.
224
- # @param constraint [String] The semver constraint to parse.
225
- # @return [T.nilable(T::Hash[Symbol, T.nilable(String)])] Returns the Ruby-compatible
226
- # constraint and the version, if available, or nil if the constraint is invalid.
227
- #
228
- # @example
229
- # to_ruby_constraint_with_version("=1.2.3") # => { constraint: "=1.2.3", version: "1.2.3" }
230
- # to_ruby_constraint_with_version("^1.2.3") # => { constraint: ">=1.2.3 <2.0.0", version: "1.2.3" }
231
- # to_ruby_constraint_with_version("*") # => { constraint: nil, version: nil }
232
- # to_ruby_constraint_with_version("invalid") # => nil
233
- sig do
234
- params(
235
- constraint: String,
236
- dependabot_versions: T.nilable(T::Array[Dependabot::Version])
237
- )
238
- .returns(T.nilable(T::Hash[Symbol, T.nilable(String)]))
239
- end
240
- def self.to_ruby_constraint_with_version(constraint, dependabot_versions = [])
241
- return nil if constraint.empty?
242
-
243
- case constraint
244
- when EXACT_CONSTRAINT_REGEX # Exact version, e.g., "1.2.3-alpha"
245
- return unless Regexp.last_match
246
-
247
- full_version = Regexp.last_match(1)
248
- { constraint: "=#{full_version}", version: full_version }
249
- when CARET_CONSTRAINT_REGEX # Caret constraint, e.g., "^1.2.3"
250
- return unless Regexp.last_match
251
-
252
- full_version = Regexp.last_match(1)
253
- _, major, minor = version_components(full_version)
254
- return nil if major.nil?
255
-
256
- ruby_constraint =
257
- if major.to_i.zero?
258
- minor.nil? ? ">=#{full_version} <1.0.0" : ">=#{full_version} <0.#{minor.to_i + 1}.0"
259
- else
260
- ">=#{full_version} <#{major.to_i + 1}.0.0"
261
- end
262
- { constraint: ruby_constraint, version: full_version }
263
- when TILDE_CONSTRAINT_REGEX # Tilde constraint, e.g., "~1.2.3"
264
- return unless Regexp.last_match
265
-
266
- full_version = Regexp.last_match(1)
267
- _, major, minor = version_components(full_version)
268
- ruby_constraint =
269
- if minor.nil?
270
- ">=#{full_version} <#{major.to_i + 1}.0.0"
271
- else
272
- ">=#{full_version} <#{major}.#{minor.to_i + 1}.0"
273
- end
274
- { constraint: ruby_constraint, version: full_version }
275
- when GREATER_THAN_EQUAL_REGEX # Greater than or equal, e.g., ">=1.2.3"
276
-
277
- return unless Regexp.last_match && Regexp.last_match(1)
278
-
279
- found_version = highest_matching_version(
280
- dependabot_versions,
281
- T.must(Regexp.last_match(1))
282
- ) do |version, constraint_version|
283
- version >= Version.new(constraint_version)
284
- end
285
- { constraint: ">=#{Regexp.last_match(1)}", version: found_version&.to_s }
286
- when LESS_THAN_EQUAL_REGEX # Less than or equal, e.g., "<=1.2.3"
287
- return unless Regexp.last_match
288
-
289
- full_version = Regexp.last_match(1)
290
- { constraint: "<=#{full_version}", version: full_version }
291
- when GREATER_THAN_REGEX # Greater than, e.g., ">1.2.3"
292
- return unless Regexp.last_match && Regexp.last_match(1)
293
-
294
- found_version = highest_matching_version(
295
- dependabot_versions,
296
- T.must(Regexp.last_match(1))
297
- ) do |version, constraint_version|
298
- version > Version.new(constraint_version)
299
- end
300
- { constraint: ">#{Regexp.last_match(1)}", version: found_version&.to_s }
301
- when LESS_THAN_REGEX # Less than, e.g., "<1.2.3"
302
- return unless Regexp.last_match && Regexp.last_match(1)
303
-
304
- found_version = highest_matching_version(
305
- dependabot_versions,
306
- T.must(Regexp.last_match(1))
307
- ) do |version, constraint_version|
308
- version < Version.new(constraint_version)
309
- end
310
- { constraint: "<#{Regexp.last_match(1)}", version: found_version&.to_s }
311
- when WILDCARD_REGEX # No specific constraint, resolves to the highest available version
312
- { constraint: nil, version: dependabot_versions&.max&.to_s }
313
- when LATEST_REGEX
314
- { constraint: nil, version: dependabot_versions&.max&.to_s } # Resolves to the latest available version
315
- end
316
- end
317
-
318
- sig do
319
- params(
320
- dependabot_versions: T.nilable(T::Array[Dependabot::Version]),
321
- constraint_version: String,
322
- condition: T.proc.params(version: Dependabot::Version, constraint: Dependabot::Version).returns(T::Boolean)
323
- )
324
- .returns(T.nilable(Dependabot::Version))
325
- end
326
- def self.highest_matching_version(dependabot_versions, constraint_version, &condition)
327
- return unless dependabot_versions&.any?
328
-
329
- # Returns the highest version that satisfies the condition, or nil if none.
330
- dependabot_versions
331
- .sort
332
- .reverse
333
- .find { |version| condition.call(version, Version.new(constraint_version)) } # rubocop:disable Performance/RedundantBlockCall
334
- end
335
-
336
- # rubocop:enable Metrics/MethodLength
337
- # rubocop:enable Metrics/PerceivedComplexity
338
- # rubocop:enable Metrics/AbcSize
339
- # rubocop:enable Metrics/CyclomaticComplexity
340
-
341
- # Parses a semantic version string into its components as per the SemVer spec
342
- # Example: "1.2.3-alpha+001" → ["1.2.3", "1", "2", "3", "alpha", "001"]
343
- sig { params(full_version: T.nilable(String)).returns(T.nilable(T::Array[String])) }
344
- def self.version_components(full_version)
345
- return [] if full_version.nil?
346
-
347
- match = full_version.match(SEMVER_VALIDATION_REGEX)
348
- return [] unless match
349
-
350
- version = match[:version]
351
- return [] unless version
352
-
353
- major, minor, patch = version.split(".")
354
- [version, major, minor, patch, match[:prerelease], match[:build]].compact
355
- end
356
- end
357
- end
358
- end
359
- end
@@ -1,164 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- # lots of sub-projects that don't all have the same dependencies.
5
- module Dependabot
6
- module Javascript
7
- module Shared
8
- class DependencyFilesFilterer
9
- extend T::Sig
10
-
11
- sig do
12
- params(
13
- dependency_files: T::Array[DependencyFile],
14
- updated_dependencies: T::Array[Dependency],
15
- lockfile_parser_class: T.class_of(FileParser::LockfileParser)
16
- )
17
- .void
18
- end
19
- def initialize(dependency_files:, updated_dependencies:, lockfile_parser_class:)
20
- @dependency_files = dependency_files
21
- @updated_dependencies = updated_dependencies
22
- @lockfile_parser_class = lockfile_parser_class
23
- end
24
-
25
- sig { returns(T::Array[String]) }
26
- def paths_requiring_update_check
27
- @paths_requiring_update_check ||= T.let(fetch_paths_requiring_update_check, T.nilable(T::Array[String]))
28
- end
29
-
30
- sig { returns(T::Array[Dependabot::DependencyFile]) }
31
- def files_requiring_update
32
- @files_requiring_update ||= T.let(
33
- dependency_files.select do |file|
34
- package_files_requiring_update.include?(file) ||
35
- package_required_lockfile?(file) ||
36
- workspaces_lockfile?(file)
37
- end, T.nilable(T::Array[DependencyFile])
38
- )
39
- end
40
-
41
- sig { returns(T::Array[Dependabot::DependencyFile]) }
42
- def package_files_requiring_update
43
- @package_files_requiring_update ||= T.let(
44
- dependency_files.select do |file|
45
- dependency_manifest_requirements.include?(file.name)
46
- end, T.nilable(T::Array[DependencyFile])
47
- )
48
- end
49
-
50
- private
51
-
52
- sig { returns(T::Array[DependencyFile]) }
53
- attr_reader :dependency_files
54
-
55
- sig { returns(T::Array[Dependency]) }
56
- attr_reader :updated_dependencies
57
-
58
- sig { returns(T.class_of(FileParser::LockfileParser)) }
59
- attr_reader :lockfile_parser_class
60
-
61
- sig { returns(T::Array[String]) }
62
- def fetch_paths_requiring_update_check
63
- # if only a root lockfile exists, it tracks all dependencies
64
- return [File.dirname(T.must(root_lockfile).name)] if lockfiles == [root_lockfile]
65
-
66
- package_files_requiring_update.map do |file|
67
- File.dirname(file.name)
68
- end
69
- end
70
-
71
- sig { returns(T::Array[String]) }
72
- def dependency_manifest_requirements
73
- @dependency_manifest_requirements ||= T.let(
74
- updated_dependencies.flat_map do |dep|
75
- dep.requirements.map { |requirement| requirement[:file] }
76
- end, T.nilable(T::Array[String])
77
- )
78
- end
79
-
80
- sig { params(lockfile: DependencyFile).returns(T::Boolean) }
81
- def package_required_lockfile?(lockfile)
82
- return false unless lockfile?(lockfile)
83
-
84
- package_files_requiring_update.any? do |package_file|
85
- File.dirname(package_file.name) == File.dirname(lockfile.name)
86
- end
87
- end
88
-
89
- sig { params(lockfile: DependencyFile).returns(T::Boolean) }
90
- def workspaces_lockfile?(lockfile)
91
- return false unless ["yarn.lock", "package-lock.json", "pnpm-lock.yaml", "bun.lock"].include?(lockfile.name)
92
-
93
- return false unless parsed_root_package_json["workspaces"] || dependency_files.any? do |file|
94
- file.name.end_with?("pnpm-workspace.yaml") && File.dirname(file.name) == File.dirname(lockfile.name)
95
- end
96
-
97
- updated_dependencies_in_lockfile?(lockfile)
98
- end
99
-
100
- sig { returns(T.nilable(DependencyFile)) }
101
- def root_lockfile
102
- @root_lockfile ||= T.let(
103
- lockfiles.find do |file|
104
- File.dirname(file.name) == "."
105
- end, T.nilable(DependencyFile)
106
- )
107
- end
108
-
109
- sig { returns(T::Array[DependencyFile]) }
110
- def lockfiles
111
- @lockfiles ||= T.let(
112
- dependency_files.select do |file|
113
- lockfile?(file)
114
- end, T.nilable(T::Array[DependencyFile])
115
- )
116
- end
117
-
118
- sig { returns(T::Hash[String, T.untyped]) }
119
- def parsed_root_package_json
120
- @parsed_root_package_json ||= T.let(
121
- begin
122
- package = T.must(dependency_files.find { |f| f.name == "package.json" })
123
- JSON.parse(T.must(package.content))
124
- end, T.nilable(T::Hash[String, T.untyped])
125
- )
126
- end
127
-
128
- sig { params(lockfile: Dependabot::DependencyFile).returns(T::Boolean) }
129
- def updated_dependencies_in_lockfile?(lockfile)
130
- lockfile_dependencies(lockfile).any? do |sub_dep|
131
- updated_dependencies.any? do |updated_dep|
132
- sub_dep.name == updated_dep.name
133
- end
134
- end
135
- end
136
-
137
- sig { params(lockfile: DependencyFile).returns(T::Array[Dependency]) }
138
- def lockfile_dependencies(lockfile)
139
- @lockfile_dependencies ||= T.let({}, T.nilable(T::Hash[String, T::Array[Dependency]]))
140
- @lockfile_dependencies[lockfile.name] ||=
141
- lockfile_parser_class.new(
142
- dependency_files: [lockfile]
143
- ).parse
144
- end
145
-
146
- sig { params(file: DependencyFile).returns(T::Boolean) }
147
- def manifest?(file)
148
- file.name.end_with?("package.json")
149
- end
150
-
151
- sig { params(file: DependencyFile).returns(T::Boolean) }
152
- def lockfile?(file)
153
- file.name.end_with?(
154
- "package-lock.json",
155
- "yarn.lock",
156
- "pnpm-lock.yaml",
157
- "bun.lock",
158
- "npm-shrinkwrap.json"
159
- )
160
- end
161
- end
162
- end
163
- end
164
- end