dependabot-bun 0.296.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aec5d70543afebc798276a80ab116a1375a90395a66815467b48ffc778f1287c
4
+ data.tar.gz: f44ddcdc48fee485db9e56d97c06040e9bcf597b42b057be8a98ca4eadbc7665
5
+ SHA512:
6
+ metadata.gz: ad382c4264db5281a25cd912a5379316e175efef2c4188e89d05699eeffc753d6114fd9046ba7fafe5bf979fd83c7ad5ec7cc2bec3237aa477d42bb19dd3b7c8
7
+ data.tar.gz: fd61ab1f24b72c1306b2b187728cfc45581740515d7000a6026bde6c5313b3e7bf3e05af3ce0e77a3d0af530e4a09a3f5b26ab518c577ef4fef5176431e44fe3
@@ -0,0 +1,97 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Bun
6
+ class FileFetcher < Dependabot::FileFetchers::Base
7
+ include Javascript::FileFetcherHelper
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
12
+ def self.required_files_in?(filenames)
13
+ filenames.include?("package.json")
14
+ end
15
+
16
+ sig { override.returns(String) }
17
+ def self.required_files_message
18
+ "Repo must contain a package.json."
19
+ end
20
+
21
+ sig { override.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
22
+ def ecosystem_versions
23
+ return unknown_ecosystem_versions unless ecosystem_enabled?
24
+
25
+ {
26
+ package_managers: {
27
+ "bun" => 1
28
+ }
29
+ }
30
+ end
31
+
32
+ sig { override.returns(T::Array[DependencyFile]) }
33
+ def fetch_files
34
+ fetched_files = T.let([], T::Array[DependencyFile])
35
+ fetched_files << package_json(self)
36
+ fetched_files += bun_files if ecosystem_enabled?
37
+ fetched_files += workspace_package_jsons(self)
38
+ fetched_files += path_dependencies(self, fetched_files)
39
+
40
+ fetched_files.uniq
41
+ end
42
+
43
+ sig { params(filename: String, fetch_submodules: T::Boolean).returns(DependencyFile) }
44
+ def fetch_file(filename, fetch_submodules: false)
45
+ fetch_file_from_host(filename, fetch_submodules: fetch_submodules)
46
+ end
47
+
48
+ sig do
49
+ params(
50
+ dir: T.any(Pathname, String),
51
+ ignore_base_directory: T::Boolean,
52
+ raise_errors: T::Boolean,
53
+ fetch_submodules: T::Boolean
54
+ )
55
+ .returns(T::Array[T.untyped])
56
+ end
57
+ def fetch_repo_contents(dir: ".", ignore_base_directory: false, raise_errors: true, fetch_submodules: false)
58
+ repo_contents(dir: dir, ignore_base_directory:, raise_errors:, fetch_submodules:)
59
+ end
60
+
61
+ private
62
+
63
+ sig { returns(T::Array[DependencyFile]) }
64
+ def bun_files
65
+ [bun_lock].compact
66
+ end
67
+
68
+ sig { returns(T.nilable(DependencyFile)) }
69
+ def bun_lock
70
+ return @bun_lock if defined?(@bun_lock)
71
+
72
+ @bun_lock ||= T.let(fetch_file_if_present(PackageManager::LOCKFILE_NAME), T.nilable(DependencyFile))
73
+
74
+ return @bun_lock if @bun_lock || directory == "/"
75
+
76
+ @bun_lock = fetch_file_from_parent_directories(self, PackageManager::LOCKFILE_NAME)
77
+ end
78
+
79
+ sig { returns(T::Boolean) }
80
+ def ecosystem_enabled?
81
+ allow_beta_ecosystems? && Experiments.enabled?(:enable_bun_ecosystem)
82
+ end
83
+
84
+ sig { returns(T::Hash[Symbol, String]) }
85
+ def unknown_ecosystem_versions
86
+ {
87
+ package_managers: {
88
+ "unknown" => 0
89
+ }
90
+ }
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ Dependabot::FileFetchers
97
+ .register(Dependabot::Bun::ECOSYSTEM, Dependabot::Bun::FileFetcher)
@@ -0,0 +1,148 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "yaml"
5
+ require "sorbet-runtime"
6
+
7
+ module Dependabot
8
+ module Bun
9
+ class FileParser < Dependabot::FileParsers::Base
10
+ class BunLock
11
+ extend T::Sig
12
+
13
+ sig { params(dependency_file: DependencyFile).void }
14
+ def initialize(dependency_file)
15
+ @dependency_file = dependency_file
16
+ end
17
+
18
+ sig { returns(T::Hash[String, T.untyped]) }
19
+ def parsed
20
+ @parsed ||= begin
21
+ content = begin
22
+ # Since bun.lock is a JSONC file, which is a subset of YAML, we can use YAML to parse it
23
+ YAML.load(T.must(@dependency_file.content))
24
+ rescue Psych::SyntaxError => e
25
+ raise_invalid!("malformed JSONC at line #{e.line}, column #{e.column}")
26
+ end
27
+ raise_invalid!("expected to be an object") unless content.is_a?(Hash)
28
+
29
+ version = content["lockfileVersion"]
30
+ raise_invalid!("expected 'lockfileVersion' to be an integer") unless version.is_a?(Integer)
31
+ raise_invalid!("expected 'lockfileVersion' to be >= 0") unless version >= 0
32
+
33
+ T.let(content, T.untyped)
34
+ end
35
+ end
36
+
37
+ sig { returns(Dependabot::FileParsers::Base::DependencySet) }
38
+ def dependencies
39
+ dependency_set = Dependabot::FileParsers::Base::DependencySet.new
40
+
41
+ # bun.lock v0 format:
42
+ # https://github.com/oven-sh/bun/blob/c130df6c589fdf28f9f3c7f23ed9901140bc9349/src/install/bun.lock.zig#L595-L605
43
+
44
+ packages = parsed["packages"]
45
+ raise_invalid!("expected 'packages' to be an object") unless packages.is_a?(Hash)
46
+
47
+ packages.each do |key, details|
48
+ raise_invalid!("expected 'packages.#{key}' to be an array") unless details.is_a?(Array)
49
+
50
+ resolution = details.first
51
+ raise_invalid!("expected 'packages.#{key}[0]' to be a string") unless resolution.is_a?(String)
52
+
53
+ name, version = resolution.split(/(?<=\w)\@/)
54
+ next if name.empty?
55
+
56
+ semver = Version.semver_for(version)
57
+ next unless semver
58
+
59
+ dependency_set << Dependency.new(
60
+ name: name,
61
+ version: semver.to_s,
62
+ package_manager: "npm_and_yarn",
63
+ requirements: []
64
+ )
65
+ end
66
+
67
+ dependency_set
68
+ end
69
+
70
+ sig do
71
+ params(dependency_name: String, requirement: T.untyped, _manifest_name: String)
72
+ .returns(T.nilable(T::Hash[String, T.untyped]))
73
+ end
74
+ def details(dependency_name, requirement, _manifest_name)
75
+ packages = parsed["packages"]
76
+ return unless packages.is_a?(Hash)
77
+
78
+ candidates =
79
+ packages
80
+ .select { |name, _| name == dependency_name }
81
+ .values
82
+
83
+ # If there's only one entry for this dependency, use it, even if
84
+ # the requirement in the lockfile doesn't match
85
+ if candidates.one?
86
+ parse_details(candidates.first)
87
+ else
88
+ candidate = candidates.find do |label, _|
89
+ label.scan(/(?<=\w)\@(?:npm:)?([^\s,]+)/).flatten.include?(requirement)
90
+ end&.last
91
+ parse_details(candidate)
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ sig { params(message: String).void }
98
+ def raise_invalid!(message)
99
+ raise Dependabot::DependencyFileNotParseable.new(@dependency_file.path, "Invalid bun.lock file: #{message}")
100
+ end
101
+
102
+ sig do
103
+ params(entry: T.nilable(T::Array[T.untyped])).returns(T.nilable(T::Hash[String, T.untyped]))
104
+ end
105
+ def parse_details(entry)
106
+ return unless entry.is_a?(Array)
107
+
108
+ # Either:
109
+ # - "{name}@{version}", registry, details, integrity
110
+ # - "{name}@{resolution}", details
111
+ resolution = entry.first
112
+ return unless resolution.is_a?(String)
113
+
114
+ name, version = resolution.split(/(?<=\w)\@/)
115
+ semver = Version.semver_for(version)
116
+
117
+ if semver
118
+ registry, details, integrity = entry[1..3]
119
+ {
120
+ "name" => name,
121
+ "version" => semver.to_s,
122
+ "registry" => registry,
123
+ "details" => details,
124
+ "integrity" => integrity
125
+ }
126
+ else
127
+ details = entry[1]
128
+ {
129
+ "name" => name,
130
+ "resolution" => version,
131
+ "details" => details
132
+ }
133
+ end
134
+ end
135
+ end
136
+
137
+ sig { override.returns(T::Array[Dependabot::Dependency]) }
138
+ def parse
139
+ []
140
+ end
141
+
142
+ private
143
+
144
+ sig { override.void }
145
+ def check_required_files; end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,79 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Bun
6
+ module Helpers
7
+ extend T::Sig
8
+
9
+ # BUN Version Constants
10
+ BUN_V1 = 1
11
+ BUN_DEFAULT_VERSION = BUN_V1
12
+
13
+ sig { params(_bun_lock: T.nilable(DependencyFile)).returns(Integer) }
14
+ def self.bun_version_numeric(_bun_lock)
15
+ BUN_DEFAULT_VERSION
16
+ end
17
+
18
+ sig { returns(T.nilable(String)) }
19
+ def self.bun_version
20
+ run_bun_command("--version", fingerprint: "--version").strip
21
+ rescue StandardError => e
22
+ Dependabot.logger.error("Error retrieving Bun version: #{e.message}")
23
+ nil
24
+ end
25
+
26
+ sig { params(command: String, fingerprint: T.nilable(String)).returns(String) }
27
+ def self.run_bun_command(command, fingerprint: nil)
28
+ full_command = "bun #{command}"
29
+
30
+ Dependabot.logger.info("Running bun command: #{full_command}")
31
+
32
+ result = Dependabot::SharedHelpers.run_shell_command(
33
+ full_command,
34
+ fingerprint: "bun #{fingerprint || command}"
35
+ )
36
+
37
+ Dependabot.logger.info("Command executed successfully: #{full_command}")
38
+ result
39
+ rescue StandardError => e
40
+ Dependabot.logger.error("Error running bun command: #{full_command}, Error: #{e.message}")
41
+ raise
42
+ end
43
+
44
+ # Fetch the currently installed version of the package manager directly
45
+ # from the system
46
+ sig { params(name: String).returns(String) }
47
+ def self.local_package_manager_version(name)
48
+ Dependabot::SharedHelpers.run_shell_command(
49
+ "#{name} -v",
50
+ fingerprint: "#{name} -v"
51
+ ).strip
52
+ end
53
+
54
+ # Run single command on package manager returning stdout/stderr
55
+ sig do
56
+ params(
57
+ name: String,
58
+ command: String,
59
+ fingerprint: T.nilable(String)
60
+ ).returns(String)
61
+ end
62
+ def self.package_manager_run_command(name, command, fingerprint: nil)
63
+ return run_bun_command(command, fingerprint: fingerprint) if name == PackageManager::NAME
64
+
65
+ # TODO: remove this method and just use the one in the PackageManager class
66
+ "noop"
67
+ end
68
+
69
+ sig { params(dependency_set: Dependabot::FileParsers::Base::DependencySet).returns(T::Array[Dependency]) }
70
+ def self.dependencies_with_all_versions_metadata(dependency_set)
71
+ # TODO: Check if we still need this method
72
+ dependency_set.dependencies.map do |dependency|
73
+ dependency.metadata[:all_versions] = dependency_set.all_versions_for_name(dependency.name)
74
+ dependency
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,45 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "dependabot/npm_and_yarn/package_manager"
5
+
6
+ module Dependabot
7
+ module Bun
8
+ class Language < Ecosystem::VersionManager
9
+ extend T::Sig
10
+ NAME = "node"
11
+
12
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
13
+
14
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
15
+
16
+ sig do
17
+ params(
18
+ detected_version: T.nilable(String),
19
+ raw_version: T.nilable(String),
20
+ requirement: T.nilable(Dependabot::NpmAndYarn::Requirement)
21
+ ).void
22
+ end
23
+ def initialize(detected_version: nil, raw_version: nil, requirement: nil)
24
+ super(
25
+ name: NAME,
26
+ detected_version: detected_version ? Version.new(detected_version) : nil,
27
+ version: raw_version ? Version.new(raw_version) : nil,
28
+ deprecated_versions: DEPRECATED_VERSIONS,
29
+ supported_versions: SUPPORTED_VERSIONS,
30
+ requirement: requirement
31
+ )
32
+ end
33
+
34
+ sig { override.returns(T::Boolean) }
35
+ def deprecated?
36
+ false
37
+ end
38
+
39
+ sig { override.returns(T::Boolean) }
40
+ def unsupported?
41
+ false
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Bun
6
+ class PackageManager < Ecosystem::VersionManager
7
+ extend T::Sig
8
+ NAME = "bun"
9
+ LOCKFILE_NAME = "bun.lock"
10
+
11
+ # In Bun 1.1.39, the lockfile format was changed from a binary bun.lockb to a text-based bun.lock.
12
+ # https://bun.sh/blog/bun-lock-text-lockfile
13
+ MIN_SUPPORTED_VERSION = T.let(Version.new("1.1.39"), Javascript::Version)
14
+ SUPPORTED_VERSIONS = T.let([MIN_SUPPORTED_VERSION].freeze, T::Array[Javascript::Version])
15
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Version])
16
+
17
+ sig do
18
+ params(
19
+ detected_version: T.nilable(String),
20
+ raw_version: T.nilable(String),
21
+ requirement: T.nilable(Requirement)
22
+ ).void
23
+ end
24
+ def initialize(detected_version: nil, raw_version: nil, requirement: nil)
25
+ super(
26
+ name: NAME,
27
+ detected_version: detected_version ? Version.new(detected_version) : nil,
28
+ version: raw_version ? Version.new(raw_version) : nil,
29
+ deprecated_versions: DEPRECATED_VERSIONS,
30
+ supported_versions: SUPPORTED_VERSIONS,
31
+ requirement: requirement
32
+ )
33
+ end
34
+
35
+ sig { override.returns(T::Boolean) }
36
+ def deprecated?
37
+ false
38
+ end
39
+
40
+ sig { override.returns(T::Boolean) }
41
+ def unsupported?
42
+ false
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Bun
6
+ class Requirement < Dependabot::Javascript::Requirement
7
+ end
8
+ end
9
+ end
10
+
11
+ Dependabot::Utils.register_requirement_class(
12
+ "bun",
13
+ Dependabot::Bun::Requirement
14
+ )
@@ -0,0 +1,12 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Bun
6
+ class Version < Dependabot::Javascript::Version
7
+ end
8
+ end
9
+ end
10
+
11
+ Dependabot::Utils
12
+ .register_version_class("bun", Dependabot::Bun::Version)
@@ -0,0 +1,39 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "zeitwerk"
5
+
6
+ loader = Zeitwerk::Loader.new
7
+
8
+ # Set autoload paths for common/lib, excluding files whose content does not match the filename
9
+ loader.push_dir(File.join(__dir__, "../../../common/lib"))
10
+ loader.ignore(File.join(__dir__, "../../../common/lib/dependabot/errors.rb"))
11
+ loader.ignore(File.join(__dir__, "../../../common/lib/dependabot/logger.rb"))
12
+ loader.ignore(File.join(__dir__, "../../../common/lib/dependabot/notices.rb"))
13
+ loader.ignore(File.join(__dir__, "../../../common/lib/dependabot/clients/codecommit.rb"))
14
+
15
+ loader.push_dir(File.join(__dir__, ".."))
16
+ loader.ignore("#{__dir__}/../script", "#{__dir__}/../spec", "#{__dir__}/../dependabot-bun.gemspec")
17
+
18
+ loader.on_load do |_file|
19
+ require "json"
20
+ require "sorbet-runtime"
21
+ require "dependabot/errors"
22
+ require "dependabot/logger"
23
+ require "dependabot/notices"
24
+ require "dependabot/clients/codecommit"
25
+ end
26
+
27
+ loader.log! if ENV["DEBUG"]
28
+ loader.setup
29
+
30
+ Dependabot::PullRequestCreator::Labeler
31
+ .register_label_details("bun", name: "javascript", colour: "168700")
32
+
33
+ Dependabot::Dependency.register_production_check("bun", ->(_) { true })
34
+
35
+ module Dependabot
36
+ module Bun
37
+ ECOSYSTEM = "bun"
38
+ end
39
+ end
@@ -0,0 +1,245 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Javascript
6
+ module FileFetcherHelper
7
+ include Kernel
8
+ extend T::Sig
9
+
10
+ PATH_DEPENDENCY_STARTS = T.let(%w(file: / ./ ../ ~/).freeze, [String, String, String, String, String])
11
+ PATH_DEPENDENCY_CLEAN_REGEX = /^file:|^link:/
12
+ DEPENDENCY_TYPES = T.let(%w(dependencies devDependencies optionalDependencies).freeze, T::Array[String])
13
+
14
+ sig { params(instance: Dependabot::Bun::FileFetcher).returns(T::Array[DependencyFile]) }
15
+ def workspace_package_jsons(instance)
16
+ @workspace_package_jsons ||= T.let(fetch_workspace_package_jsons(instance), T.nilable(T::Array[DependencyFile]))
17
+ end
18
+
19
+ sig do
20
+ params(instance: Dependabot::Bun::FileFetcher, fetched_files: T::Array[DependencyFile])
21
+ .returns(T::Array[DependencyFile])
22
+ end
23
+ def path_dependencies(instance, fetched_files)
24
+ package_json_files = T.let([], T::Array[DependencyFile])
25
+
26
+ path_dependency_details(instance, fetched_files).each do |name, path|
27
+ # This happens with relative paths in the package-lock. Skipping it since it results
28
+ # in /package.json which is outside of the project directory.
29
+ next if path == "file:"
30
+
31
+ path = path.gsub(PATH_DEPENDENCY_CLEAN_REGEX, "")
32
+ raise PathDependenciesNotReachable, "#{name} at #{path}" if path.start_with?("/")
33
+
34
+ filename = path
35
+ filename = File.join(filename, MANIFEST_FILENAME)
36
+ cleaned_name = Pathname.new(filename).cleanpath.to_path
37
+ next if fetched_files.map(&:name).include?(cleaned_name)
38
+
39
+ file = instance.fetch_file(filename, fetch_submodules: true)
40
+ package_json_files << file
41
+ end
42
+
43
+ if package_json_files.any?
44
+ package_json_files +=
45
+ path_dependencies(instance, fetched_files + package_json_files)
46
+ end
47
+
48
+ package_json_files.tap { |fs| fs.each { |f| f.support_file = true } }
49
+ end
50
+
51
+ sig do
52
+ params(instance: Dependabot::Bun::FileFetcher, fetched_files: T::Array[DependencyFile])
53
+ .returns(T::Array[[String, String]])
54
+ end
55
+ def path_dependency_details(instance, fetched_files)
56
+ package_json_path_deps = T.let([], T::Array[[String, String]])
57
+
58
+ fetched_files.each do |file|
59
+ package_json_path_deps +=
60
+ path_dependency_details_from_manifest(instance, file)
61
+ end
62
+
63
+ [
64
+ *package_json_path_deps
65
+ ].uniq
66
+ end
67
+
68
+ # rubocop:disable Metrics/PerceivedComplexity
69
+ # rubocop:disable Metrics/AbcSize
70
+ sig { params(instance: Dependabot::Bun::FileFetcher, file: DependencyFile).returns(T::Array[[String, String]]) }
71
+ def path_dependency_details_from_manifest(instance, file)
72
+ return [] unless file.name.end_with?(MANIFEST_FILENAME)
73
+
74
+ current_dir = file.name.rpartition("/").first
75
+ current_dir = nil if current_dir == ""
76
+
77
+ current_depth = File.join(instance.directory, file.name).split("/").count { |path| !path.empty? }
78
+ path_to_directory = "../" * current_depth
79
+
80
+ dep_types = DEPENDENCY_TYPES # TODO: Is this needed?
81
+ parsed_manifest = JSON.parse(T.must(file.content))
82
+ dependency_objects = parsed_manifest.values_at(*dep_types).compact
83
+ # Fetch yarn "file:" path "resolutions" so the lockfile can be resolved
84
+ resolution_objects = parsed_manifest.values_at("resolutions").compact
85
+ manifest_objects = dependency_objects + resolution_objects
86
+
87
+ raise Dependabot::DependencyFileNotParseable, file.path unless manifest_objects.all?(Hash)
88
+
89
+ resolution_deps = resolution_objects.flat_map(&:to_a)
90
+ .map do |path, value|
91
+ # skip dependencies that contain invalid values such as inline comments, null, etc.
92
+
93
+ unless value.is_a?(String)
94
+ Dependabot.logger.warn("File fetcher: Skipping dependency \"#{path}\" " \
95
+ "with value: \"#{value}\"")
96
+
97
+ next
98
+ end
99
+
100
+ convert_dependency_path_to_name(path, value)
101
+ end
102
+
103
+ path_starts = PATH_DEPENDENCY_STARTS
104
+ (dependency_objects.flat_map(&:to_a) + resolution_deps)
105
+ .select { |_, v| v.is_a?(String) && v.start_with?(*path_starts) }
106
+ .map do |name, path|
107
+ path = path.gsub(PATH_DEPENDENCY_CLEAN_REGEX, "")
108
+ raise PathDependenciesNotReachable, "#{name} at #{path}" if path.start_with?("/", "#{path_to_directory}..")
109
+
110
+ path = File.join(current_dir, path) unless current_dir.nil?
111
+ [name, Pathname.new(path).cleanpath.to_path]
112
+ end
113
+ rescue JSON::ParserError
114
+ raise Dependabot::DependencyFileNotParseable, file.path
115
+ end
116
+ # rubocop:enable Metrics/AbcSize
117
+ # rubocop:enable Metrics/PerceivedComplexity
118
+
119
+ # Re-write the glob name to the targeted dependency name (which is used
120
+ # in the lockfile), for example "parent-package/**/sub-dep/target-dep" >
121
+ # "target-dep"
122
+ sig { params(path: String, value: String).returns([String, String]) }
123
+ def convert_dependency_path_to_name(path, value)
124
+ # Picking the last two parts that might include a scope
125
+ parts = path.split("/").last(2)
126
+ parts.shift if parts.count == 2 && !T.must(parts.first).start_with?("@")
127
+ [parts.join("/"), value]
128
+ end
129
+
130
+ sig { params(instance: Dependabot::Bun::FileFetcher).returns(T::Array[DependencyFile]) }
131
+ def fetch_workspace_package_jsons(instance)
132
+ parsed_manifest = parsed_package_json(instance)
133
+ return [] unless parsed_manifest["workspaces"]
134
+
135
+ workspace_paths(instance, parsed_manifest["workspaces"]).filter_map do |workspace|
136
+ fetch_package_json_if_present(instance, workspace)
137
+ end
138
+ end
139
+
140
+ sig { params(instance: Dependabot::Bun::FileFetcher, workspace_object: T.untyped).returns(T::Array[String]) }
141
+ def workspace_paths(instance, workspace_object)
142
+ paths_array =
143
+ if workspace_object.is_a?(Hash)
144
+ workspace_object.values_at("packages", "nohoist").flatten.compact
145
+ elsif workspace_object.is_a?(Array) then workspace_object
146
+ else
147
+ [] # Invalid lerna.json, which must not be in use
148
+ end
149
+
150
+ paths_array.flat_map { |path| recursive_find_directories(instance, path) }
151
+ end
152
+
153
+ sig { params(instance: Dependabot::Bun::FileFetcher, glob: String).returns(T::Array[String]) }
154
+ def find_directories(instance, glob)
155
+ return [glob] unless glob.include?("*")
156
+
157
+ unglobbed_path =
158
+ glob.gsub(%r{^\./}, "").gsub(/!\(.*?\)/, "*")
159
+ .split("*")
160
+ .first&.gsub(%r{(?<=/)[^/]*$}, "") || "."
161
+
162
+ dir = instance.directory.gsub(%r{(^/|/$)}, "")
163
+
164
+ paths =
165
+ instance.fetch_repo_contents(dir: unglobbed_path, raise_errors: false)
166
+ .select { |file| file.type == "dir" }
167
+ .map { |f| f.path.gsub(%r{^/?#{Regexp.escape(dir)}/?}, "") }
168
+
169
+ matching_paths(glob, paths)
170
+ end
171
+
172
+ sig { params(glob: String, paths: T::Array[String]).returns(T::Array[String]) }
173
+ def matching_paths(glob, paths)
174
+ glob = glob.gsub(%r{^\./}, "").gsub(/!\(.*?\)/, "*")
175
+ glob = "#{glob}/*" if glob.end_with?("**")
176
+
177
+ paths.select { |filename| File.fnmatch?(glob, filename, File::FNM_PATHNAME) }
178
+ end
179
+
180
+ sig { params(instance: Dependabot::Bun::FileFetcher, glob: String, prefix: String).returns(T::Array[String]) }
181
+ def recursive_find_directories(instance, glob, prefix = "")
182
+ return [prefix + glob] unless glob.include?("*")
183
+
184
+ glob = glob.gsub(%r{^\./}, "")
185
+ glob_parts = glob.split("/")
186
+
187
+ current_glob = glob_parts.first
188
+ paths = find_directories(instance, prefix + T.must(current_glob))
189
+ next_parts = current_glob == "**" ? glob_parts : glob_parts.drop(1)
190
+ return paths if next_parts.empty?
191
+
192
+ paths += paths.flat_map do |expanded_path|
193
+ recursive_find_directories(instance, next_parts.join("/"), "#{expanded_path}/")
194
+ end
195
+
196
+ matching_paths(prefix + glob, paths)
197
+ end
198
+
199
+ sig { params(instance: Dependabot::Bun::FileFetcher, workspace: String).returns(T.nilable(DependencyFile)) }
200
+ def fetch_package_json_if_present(instance, workspace)
201
+ file = File.join(workspace, MANIFEST_FILENAME)
202
+
203
+ begin
204
+ instance.fetch_file(file)
205
+ rescue Dependabot::DependencyFileNotFound
206
+ # Not all paths matched by a workspace glob may contain a package.json
207
+ # file. Ignore if that's the case
208
+ nil
209
+ end
210
+ end
211
+
212
+ sig { params(instance: Dependabot::Bun::FileFetcher).returns(DependencyFile) }
213
+ def package_json(instance)
214
+ @package_json ||= T.let(instance.fetch_file(Javascript::MANIFEST_FILENAME), T.nilable(DependencyFile))
215
+ end
216
+
217
+ sig { params(instance: Dependabot::Bun::FileFetcher).returns(T.untyped) }
218
+ def parsed_package_json(instance)
219
+ manifest_file = package_json(instance)
220
+ parsed = JSON.parse(T.must(manifest_file.content))
221
+ raise Dependabot::DependencyFileNotParseable, manifest_file.path unless parsed.is_a?(Hash)
222
+
223
+ parsed
224
+ rescue JSON::ParserError
225
+ raise Dependabot::DependencyFileNotParseable, T.must(manifest_file).path
226
+ end
227
+
228
+ sig { params(instance: Dependabot::Bun::FileFetcher, filename: String).returns(T.nilable(DependencyFile)) }
229
+ def fetch_file_with_support(instance, filename)
230
+ instance.fetch_file(filename).tap { |f| f.support_file = true }
231
+ rescue Dependabot::DependencyFileNotFound
232
+ nil
233
+ end
234
+
235
+ sig { params(instance: Dependabot::Bun::FileFetcher, filename: String).returns(T.nilable(DependencyFile)) }
236
+ def fetch_file_from_parent_directories(instance, filename)
237
+ (1..instance.directory.split("/").count).each do |i|
238
+ file = fetch_file_with_support(instance, ("../" * i) + filename)
239
+ return file if file
240
+ end
241
+ nil
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,141 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ require "dependabot/requirement"
7
+ require "dependabot/utils"
8
+ require "dependabot/npm_and_yarn/version"
9
+
10
+ module Dependabot
11
+ module Javascript
12
+ class Requirement < Dependabot::Requirement
13
+ extend T::Sig
14
+
15
+ AND_SEPARATOR = /(?<=[a-zA-Z0-9*])\s+(?:&+\s+)?(?!\s*[|-])/
16
+ OR_SEPARATOR = /(?<=[a-zA-Z0-9*])\s*\|+/
17
+
18
+ # Override the version pattern to allow a 'v' prefix
19
+ quoted = OPS.keys.map { |k| Regexp.quote(k) }.join("|")
20
+ version_pattern = "v?#{Javascript::Version::VERSION_PATTERN}"
21
+
22
+ PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{version_pattern})\\s*".freeze
23
+ PATTERN = /\A#{PATTERN_RAW}\z/
24
+
25
+ def self.parse(obj)
26
+ return ["=", nil] if obj.is_a?(String) && Version::VERSION_TAGS.include?(obj.strip)
27
+ return ["=", Javascript::Version.new(obj.to_s)] if obj.is_a?(Gem::Version)
28
+
29
+ unless (matches = PATTERN.match(obj.to_s))
30
+ msg = "Illformed requirement [#{obj.inspect}]"
31
+ raise BadRequirementError, msg
32
+ end
33
+
34
+ return DefaultRequirement if matches[1] == ">=" && matches[2] == "0"
35
+
36
+ [matches[1] || "=", Javascript::Version.new(T.must(matches[2]))]
37
+ end
38
+
39
+ # Returns an array of requirements. At least one requirement from the
40
+ # returned array must be satisfied for a version to be valid.
41
+ sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Requirement]) }
42
+ def self.requirements_array(requirement_string)
43
+ return [new(nil)] if requirement_string.nil?
44
+
45
+ # Removing parentheses is technically wrong but they are extremely
46
+ # rarely used.
47
+ # TODO: Handle complicated parenthesised requirements
48
+ requirement_string = requirement_string.gsub(/[()]/, "")
49
+ requirement_string.strip.split(OR_SEPARATOR).map do |req_string|
50
+ requirements = req_string.strip.split(AND_SEPARATOR)
51
+ new(requirements)
52
+ end
53
+ end
54
+
55
+ def initialize(*requirements)
56
+ requirements = requirements.flatten
57
+ .flat_map { |req_string| req_string.split(",").map(&:strip) }
58
+ .flat_map { |req_string| convert_js_constraint_to_ruby_constraint(req_string) }
59
+
60
+ super(requirements)
61
+ end
62
+
63
+ private
64
+
65
+ def convert_js_constraint_to_ruby_constraint(req_string)
66
+ return req_string if req_string.match?(/^([A-Za-uw-z]|v[^\d])/)
67
+
68
+ req_string = req_string.gsub(/(?:\.|^)[xX*]/, "")
69
+
70
+ if req_string.empty? then ">= 0"
71
+ elsif req_string.start_with?("~>") then req_string
72
+ elsif req_string.start_with?("=") then req_string.gsub(/^=*/, "")
73
+ elsif req_string.start_with?("~") then convert_tilde_req(req_string)
74
+ elsif req_string.start_with?("^") then convert_caret_req(req_string)
75
+ elsif req_string.include?(" - ") then convert_hyphen_req(req_string)
76
+ elsif req_string.match?(/[<>]/) then req_string
77
+ else
78
+ ruby_range(req_string)
79
+ end
80
+ end
81
+
82
+ def convert_tilde_req(req_string)
83
+ version = req_string.gsub(/^~\>?[\s=]*/, "")
84
+ parts = version.split(".")
85
+ parts << "0" if parts.count < 3
86
+ "~> #{parts.join('.')}"
87
+ end
88
+
89
+ def convert_hyphen_req(req_string)
90
+ lower_bound, upper_bound = req_string.split(/\s+-\s+/)
91
+ lower_bound_parts = lower_bound.split(".")
92
+ lower_bound_parts.fill("0", lower_bound_parts.length...3)
93
+
94
+ upper_bound_parts = upper_bound.split(".")
95
+ upper_bound_range =
96
+ if upper_bound_parts.length < 3
97
+ # When upper bound is a partial version treat these as an X-range
98
+ upper_bound_parts[-1] = upper_bound_parts[-1].to_i + 1 if upper_bound_parts[-1].to_i.positive?
99
+ upper_bound_parts.fill("0", upper_bound_parts.length...3)
100
+ "< #{upper_bound_parts.join('.')}.a"
101
+ else
102
+ "<= #{upper_bound_parts.join('.')}"
103
+ end
104
+
105
+ [">= #{lower_bound_parts.join('.')}", upper_bound_range]
106
+ end
107
+
108
+ def ruby_range(req_string)
109
+ parts = req_string.split(".")
110
+ # If we have three or more parts then this is an exact match
111
+ return req_string if parts.count >= 3
112
+
113
+ # If we have fewer than three parts we do a partial match
114
+ parts << "0"
115
+ "~> #{parts.join('.')}"
116
+ end
117
+
118
+ def convert_caret_req(req_string)
119
+ version = req_string.gsub(/^\^[\s=]*/, "")
120
+ parts = version.split(".")
121
+ parts.fill("x", parts.length...3)
122
+ first_non_zero = parts.find { |d| d != "0" }
123
+ first_non_zero_index =
124
+ first_non_zero ? parts.index(first_non_zero) : parts.count - 1
125
+ # If the requirement has a blank minor or patch version increment the
126
+ # previous index value with 1
127
+ first_non_zero_index -= 1 if first_non_zero == "x"
128
+ upper_bound = parts.map.with_index do |part, i|
129
+ if i < first_non_zero_index then part
130
+ elsif i == first_non_zero_index then (part.to_i + 1).to_s
131
+ elsif i > first_non_zero_index && i == 2 then "0.a"
132
+ else
133
+ 0
134
+ end
135
+ end.join(".")
136
+
137
+ [">= #{version}", "< #{upper_bound}"]
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,135 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "dependabot/version"
5
+ require "dependabot/utils"
6
+ require "sorbet-runtime"
7
+
8
+ # JavaScript pre-release versions use 1.0.1-rc1 syntax, which Gem::Version
9
+ # converts into 1.0.1.pre.rc1. We override the `to_s` method to stop that
10
+ # alteration.
11
+ #
12
+ # See https://semver.org/ for details of node's version syntax.
13
+
14
+ module Dependabot
15
+ module Javascript
16
+ class Version < Dependabot::Version
17
+ extend T::Sig
18
+
19
+ sig { returns(T.nilable(String)) }
20
+ attr_reader :build_info
21
+
22
+ # These are possible npm versioning tags that can be used in place of a version.
23
+ # See https://docs.npmjs.com/cli/v10/commands/npm-dist-tag#purpose for more details.
24
+ VERSION_TAGS = T.let([
25
+ "alpha", # Alpha version, early testing phase
26
+ "beta", # Beta version, more stable than alpha
27
+ "canary", # Canary version, often used for cutting-edge builds
28
+ "dev", # Development version, ongoing development
29
+ "experimental", # Experimental version, unstable and new features
30
+ "latest", # Latest stable version, used by npm to identify the current version of a package
31
+ "legacy", # Legacy version, older version maintained for compatibility
32
+ "next", # Next version, used by some projects to identify the upcoming version
33
+ "nightly", # Nightly build, daily builds often including latest changes
34
+ "rc", # Release candidate, potential final version
35
+ "release", # General release version
36
+ "stable" # Stable version, thoroughly tested and stable
37
+ ].freeze.map(&:freeze), T::Array[String])
38
+
39
+ VERSION_PATTERN = T.let(Gem::Version::VERSION_PATTERN + '(\+[0-9a-zA-Z\-.]+)?', String)
40
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/
41
+
42
+ sig { override.params(version: VersionParameter).returns(T::Boolean) }
43
+ def self.correct?(version)
44
+ version = version.gsub(/^v/, "") if version.is_a?(String)
45
+
46
+ return false if version.nil?
47
+
48
+ version.to_s.match?(ANCHORED_VERSION_PATTERN)
49
+ end
50
+
51
+ sig { params(version: VersionParameter).returns(VersionParameter) }
52
+ def self.semver_for(version)
53
+ # The next two lines are to guard against improperly formatted
54
+ # versions in a lockfile, such as an empty string or additional
55
+ # characters. NPM/yarn fixes these when running an update, so we can
56
+ # safely ignore these versions.
57
+ return if version == ""
58
+ return unless correct?(version)
59
+
60
+ version
61
+ end
62
+
63
+ sig { override.params(version: VersionParameter).void }
64
+ def initialize(version)
65
+ version = clean_version(version)
66
+
67
+ @version_string = T.let(version.to_s, String)
68
+
69
+ @build_info = T.let(nil, T.nilable(String))
70
+
71
+ version, @build_info = version.to_s.split("+") if version.to_s.include?("+")
72
+
73
+ super(T.must(version))
74
+ end
75
+
76
+ sig { params(version: VersionParameter).returns(VersionParameter) }
77
+ def clean_version(version)
78
+ # Check if version is a string before attempting to match
79
+ if version.is_a?(String)
80
+ # Matches @ followed by x.y.z (digits separated by dots)
81
+ if (match = version.match(/@(\d+\.\d+\.\d+)/))
82
+ version = match[1] # Just "4.5.3"
83
+
84
+ # Extract version in case the output contains Corepack verbose data
85
+ elsif version.include?("Corepack")
86
+ version = T.must(T.must(version.tr("\n", " ").match(/(\d+\.\d+\.\d+)/))[-1])
87
+ end
88
+ version = version&.gsub(/^v/, "")
89
+ end
90
+
91
+ version
92
+ end
93
+
94
+ sig { override.params(version: VersionParameter).returns(Dependabot::Javascript::Version) }
95
+ def self.new(version)
96
+ T.cast(super, Dependabot::Javascript::Version)
97
+ end
98
+
99
+ sig { returns(Integer) }
100
+ def major
101
+ @major ||= T.let(segments[0].to_i, T.nilable(Integer))
102
+ end
103
+
104
+ sig { returns(Integer) }
105
+ def minor
106
+ @minor ||= T.let(segments[1].to_i, T.nilable(Integer))
107
+ end
108
+
109
+ sig { returns(Integer) }
110
+ def patch
111
+ @patch ||= T.let(segments[2].to_i, T.nilable(Integer))
112
+ end
113
+
114
+ sig { params(other: Dependabot::Javascript::Version).returns(T::Boolean) }
115
+ def backwards_compatible_with?(other)
116
+ case major
117
+ when 0
118
+ self == other
119
+ else
120
+ major == other.major && minor >= other.minor
121
+ end
122
+ end
123
+
124
+ sig { override.returns(String) }
125
+ def to_s
126
+ @version_string
127
+ end
128
+
129
+ sig { override.returns(String) }
130
+ def inspect
131
+ "#<#{self.class} #{@version_string}>"
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,8 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Javascript
6
+ MANIFEST_FILENAME = "package.json"
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,296 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dependabot-bun
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.296.0
5
+ platform: ruby
6
+ authors:
7
+ - Dependabot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-02-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dependabot-common
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.296.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.296.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: zeitwerk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: debug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.9.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.9.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: gpgme
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-its
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-sorbet
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.9.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.9.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.67.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.67.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-performance
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 1.22.1
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 1.22.1
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rspec
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 2.29.1
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 2.29.1
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop-sorbet
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 0.8.5
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 0.8.5
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 0.22.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 0.22.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: turbo_tests
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: 2.2.0
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 2.2.0
209
+ - !ruby/object:Gem::Dependency
210
+ name: vcr
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '6.1'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '6.1'
223
+ - !ruby/object:Gem::Dependency
224
+ name: webmock
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '3.18'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: '3.18'
237
+ - !ruby/object:Gem::Dependency
238
+ name: webrick
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '1.7'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '1.7'
251
+ description: Dependabot-bun provides support for bumping Javascript libraries using
252
+ bun via Dependabot. If you want support for multiple package managers, you probably
253
+ want the meta-gem dependabot-omnibus.
254
+ email: opensource@github.com
255
+ executables: []
256
+ extensions: []
257
+ extra_rdoc_files: []
258
+ files:
259
+ - lib/dependabot/bun.rb
260
+ - lib/dependabot/bun/file_fetcher.rb
261
+ - lib/dependabot/bun/file_parser/bun_lock.rb
262
+ - lib/dependabot/bun/helpers.rb
263
+ - lib/dependabot/bun/language.rb
264
+ - lib/dependabot/bun/package_manager.rb
265
+ - lib/dependabot/bun/requirement.rb
266
+ - lib/dependabot/bun/version.rb
267
+ - lib/dependabot/javascript.rb
268
+ - lib/dependabot/javascript/file_fetcher_helper.rb
269
+ - lib/dependabot/javascript/requirement.rb
270
+ - lib/dependabot/javascript/version.rb
271
+ homepage: https://github.com/dependabot/dependabot-core
272
+ licenses:
273
+ - MIT
274
+ metadata:
275
+ bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
276
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.296.0
277
+ post_install_message:
278
+ rdoc_options: []
279
+ require_paths:
280
+ - lib
281
+ required_ruby_version: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: 3.1.0
286
+ required_rubygems_version: !ruby/object:Gem::Requirement
287
+ requirements:
288
+ - - ">="
289
+ - !ruby/object:Gem::Version
290
+ version: 3.1.0
291
+ requirements: []
292
+ rubygems_version: 3.5.22
293
+ signing_key:
294
+ specification_version: 4
295
+ summary: Provides Dependabot support for Bun
296
+ test_files: []