Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ def details(dependency_name, requirement, _manifest_name)
details = if details_candidates.one?
T.must(details_candidates.first).last
else
details_candidates.find do |k, _|
k.scan(/(?<=\w)\@(?:npm:)?([^\s,]+)/).flatten.include?(requirement)
details_candidates.find do |descriptor_key, _|
descriptor_key_includes_requirement?(descriptor_key, dependency_name, requirement)
end&.last
end
return if details.nil?
Expand Down Expand Up @@ -145,6 +145,24 @@ def dealias_packages?
@dealias_packages
end

sig do
params(
descriptor_key: String,
dependency_name: String,
requirement: T.nilable(String)
)
.returns(T::Boolean)
end
def descriptor_key_includes_requirement?(descriptor_key, dependency_name, requirement)
return false unless requirement

# Requirements can contain spaces; compare complete descriptors
# rather than interpreting or truncating the range.
descriptor_key.split(/ *, */).any? do |descriptor|
descriptor == "#{dependency_name}@#{requirement}" || descriptor == "#{dependency_name}@npm:#{requirement}"
end
end

sig { params(requirement: String).returns(T::Boolean) }
def alias_package?(requirement)
requirement.match?(/@npm:(.+@(?!npm))/)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,53 @@
)
end
end

context "when an OR range shares a prefix with another requirement" do
# Keep separate aproba entries for ^1.0.3 and ^1.0.3 || ^2.0.0 to exercise descriptor matching.
let(:dependency_files) { project_dependency_files("yarn_berry/no_lockfile_change") }
let(:dependency_name) { "aproba" }
let(:requirement) { "^1.0.3 || ^2.0.0" }

it "finds the entry matching the complete descriptor" do
expect(lockfile_details).to have_attributes(
version: "2.0.0",
resolution: "aproba@npm:2.0.0"
)
end
end

context "when a scoped dependency has multiple native npm descriptors" do
# Keep both @babel/code-frame entries so the sole-candidate fallback cannot satisfy this example.
let(:dependency_files) { project_dependency_files("yarn_berry/lockfile_only_change") }
let(:dependency_name) { "@babel/code-frame" }
let(:requirement) { "^7.0.0-beta.35" }

it "finds the entry matching the complete descriptor" do
expect(lockfile_details).to have_attributes(
version: "7.0.0-beta.35",
resolution: "@babel/code-frame@npm:7.0.0-beta.35"
)
end
end

context "when a comparator range belongs to a composite descriptor" do
# Keep statuses@npm:2.0.1 alongside the grouped >= 1.5.0 < 2 and ^1.5.0 descriptors.
let(:dependency_files) { project_dependency_files("yarn/submodule_dependency") }
let(:dependency_name) { "statuses" }
let(:requirement) { ">= 1.5.0 < 2" }

it "matches the complete comparator range" do
expect(lockfile_details).to have_attributes(version: "1.5.0", resolution: "statuses@npm:1.5.0")
end

context "when the requirement matches the second descriptor" do
let(:requirement) { "^1.5.0" }

it "finds the entry matching the requirement" do
expect(lockfile_details).to have_attributes(version: "1.5.0", resolution: "statuses@npm:1.5.0")
end
end
end
end

context "when dealing with pnpm lockfiles" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,39 @@
.to have_attributes(version: "1.2.0", resolution: "example@npm:1.2.0")
end

context "when the requirement is only a prefix of another descriptor" do
let(:result) do
{
"example@npm:^1.0.0 || ^2.0.0" => {
"version" => "2.0.0",
"resolution" => "example@npm:2.0.0"
},
"example@npm:^3.0.0" => {
"version" => "3.0.0",
"resolution" => "example@npm:3.0.0"
}
}
end

it "does not match an incomplete descriptor" do
expect(reader.details("example", "^1.0.0", "package.json")).to be_nil
end
end

context "when bare descriptors contain a range with spaces" do
let(:result) do
{
"example@^1.0.0" => { "version" => "1.2.0" },
"example@^1.0.0 || ^2.0.0" => { "version" => "2.0.0" }
}
end

it "finds the entry matching the complete range" do
expect(reader.details("example", "^1.0.0 || ^2.0.0", "package.json"))
.to have_attributes(version: "2.0.0")
end
end

context "with unconsumed malformed dependency data" do
let(:entry) { super().merge("dependencies" => []) }

Expand Down
Loading