diff --git a/core/resolver/resolver.go b/core/resolver/resolver.go index 22cb1d2..af70f5f 100644 --- a/core/resolver/resolver.go +++ b/core/resolver/resolver.go @@ -63,7 +63,8 @@ func (r *Resolver) ResolvePackages() (map[string]*ResolvedPackage, error) { resolvedPackages := make(map[string]*ResolvedPackage) for name, pkg := range r.packages { - latestVersion, err := r.mise.GetLatestVersion(name, pkg.Version) + fuzzyVersion := resolveToFuzzyVersion(pkg.Version) + latestVersion, err := r.mise.GetLatestVersion(name, fuzzyVersion) if err != nil { return nil, err diff --git a/core/resolver/version.go b/core/resolver/version.go new file mode 100644 index 0000000..898d9ee --- /dev/null +++ b/core/resolver/version.go @@ -0,0 +1,38 @@ +package resolver + +import "strings" + +func resolveToFuzzyVersion(version string) string { + // Remove any whitespace + version = strings.TrimSpace(version) + + // Handle empty string and "*" cases + if version == "" || version == "*" { + return "latest" + } + + // Handle range notation (e.g. ">=22 <23") + if strings.Contains(version, ">=") || strings.Contains(version, "<") { + parts := strings.Fields(version) + // Take the first version number we find + for _, part := range parts { + if v := strings.TrimPrefix(strings.TrimPrefix(part, ">="), "<"); v != part { + version = v + break + } + } + } + + // Remove any prefix characters (^, ~, v) + version = strings.TrimPrefix(version, "^") + version = strings.TrimPrefix(version, "~") + version = strings.TrimPrefix(version, "v") + + // Replace .x with empty string (e.g. "14.x" -> "14") + version = strings.ReplaceAll(version, ".x", "") + + // Remove any trailing dots + version = strings.TrimRight(version, ".") + + return version +} diff --git a/core/resolver/version_test.go b/core/resolver/version_test.go new file mode 100644 index 0000000..8af7da5 --- /dev/null +++ b/core/resolver/version_test.go @@ -0,0 +1,38 @@ +package resolver + +import "testing" + +func TestResolveToFuzzyVersion(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + {"simple major version", "14", "14"}, + {"major.minor version", "18.2", "18.2"}, + {"major.minor.patch version", "18.3.2", "18.3.2"}, + {"x notation", "14.x", "14"}, + {"x notation with minor", "14.2.x", "14.2"}, + {"range notation", ">=22 <23", "22"}, + {"range notation with minor", ">=22.1 <23", "22.1"}, + {"range notation with patch", ">=22.1.3 <23", "22.1.3"}, + {"caret notation", "^14.3.2", "14.3.2"}, + {"caret notation minor", "^14.3", "14.3"}, + {"caret notation major", "^14", "14"}, + {"tilde notation", "~14.3.2", "14.3.2"}, + {"v prefix", "v14.3.2", "14.3.2"}, + {"empty string", "", "latest"}, + {"star wildcard", "*", "latest"}, + {"whitespace", " 14.3 ", "14.3"}, + {"multiple x", "14.x.x", "14"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := resolveToFuzzyVersion(tt.input) + if result != tt.expected { + t.Errorf("resolveToFuzzyVersion(%q) = %q, want %q", tt.input, result, tt.expected) + } + }) + } +}