@@ -842,8 +842,11 @@ class NugetVersionRange(MavenVersionRange):
842842
843843
844844class ComposerVersionRange (VersionRange ):
845- # TODO composer may need its own scheme see https//github.com/aboutcode-org/univers/issues/5
846- # and https//getcomposer.org/doc/articles/versions.md
845+ """
846+ Composer version range as documented at
847+ https://getcomposer.org/doc/articles/versions.md
848+ """
849+
847850 scheme = "composer"
848851 version_class = versions .ComposerVersion
849852
@@ -856,6 +859,75 @@ class ComposerVersionRange(VersionRange):
856859 "=" : "=" , # This is not a native composer-semver comparator, but is used in the gitlab version range for composer packages.
857860 }
858861
862+ @classmethod
863+ def from_native (cls , string ):
864+ """
865+ Parse a Composer version range string into a version range object.
866+ """
867+ string = string .strip ()
868+
869+ if string .startswith ("^" ):
870+ base_version = string [1 :]
871+ base_version_obj = cls .version_class (base_version )
872+ base_parts = base_version .split ("." )
873+ if base_parts [0 ] == "0" :
874+ upper_constraint = VersionConstraint (
875+ comparator = "<" , version = cls .version_class (f"0.{ int (base_parts [1 ]) + 1 } .0" )
876+ )
877+ else :
878+ upper_constraint = VersionConstraint (
879+ comparator = "<" , version = cls .version_class (f"{ int (base_parts [0 ]) + 1 } .0.0" )
880+ )
881+ lower_constraint = VersionConstraint (comparator = ">=" , version = base_version_obj )
882+ return cls (constraints = [lower_constraint , upper_constraint ])
883+
884+ if string .startswith ("~" ):
885+ base_version = string [1 :]
886+ base_version_obj = cls .version_class (base_version )
887+ base_parts = base_version .split ("." )
888+
889+ if len (base_parts ) == 3 :
890+ upper_constraint = VersionConstraint (
891+ comparator = "<" ,
892+ version = cls .version_class (f"{ base_parts [0 ]} .{ int (base_parts [1 ]) + 1 } .0" ),
893+ )
894+ else :
895+ upper_constraint = VersionConstraint (
896+ comparator = "<" , version = cls .version_class (f"{ int (base_parts [0 ]) + 1 } .0.0" )
897+ )
898+
899+ lower_constraint = VersionConstraint (comparator = ">=" , version = base_version_obj )
900+ return cls (constraints = [lower_constraint , upper_constraint ])
901+
902+ if ".*" in string :
903+ base_version = string .replace (".*" , ".0" )
904+ base_version_obj = cls .version_class (base_version )
905+ base_parts = base_version .split ("." )
906+ upper_constraint = VersionConstraint (
907+ comparator = "<" ,
908+ version = cls .version_class (f"{ base_parts [0 ]} .{ int (base_parts [1 ]) + 1 } .0" ),
909+ )
910+ lower_constraint = VersionConstraint (comparator = ">=" , version = base_version_obj )
911+ return cls (constraints = [lower_constraint , upper_constraint ])
912+
913+ constraints = []
914+
915+ segments = string .split ("||" )
916+
917+ for segment in segments :
918+ if not any (op in string for op in cls .vers_by_native_comparators ):
919+ segment = "==" + segment
920+ specifiers = SpecifierSet (segment )
921+ for spec in specifiers :
922+ operator = spec .operator
923+ version = spec .version
924+ version = cls .version_class (version )
925+ comparator = cls .vers_by_native_comparators .get (operator , "=" )
926+ constraint = VersionConstraint (comparator = comparator , version = version )
927+ constraints .append (constraint )
928+
929+ return cls (constraints = constraints )
930+
859931
860932class RpmVersionRange (VersionRange ):
861933 # http://ftp.rpm.org/api/4.4.2.2/dependencies.html
@@ -942,7 +1014,7 @@ def from_natives(cls, strings):
9421014
9431015class GolangVersionRange (VersionRange ):
9441016 """
945- Go modules use strict semver with pseudo numbering for Git repos
1017+ Go modules use strict semver with pseudo numbering for Git commits.
9461018 https://go.dev/doc/modules/version-numbers
9471019 """
9481020
@@ -958,6 +1030,39 @@ class GolangVersionRange(VersionRange):
9581030 "=" : "=" , # This is not a native golang-semver comparator, but is used in the gitlab version range for go packages.
9591031 }
9601032
1033+ @classmethod
1034+ def from_native (cls , string ):
1035+ """
1036+ Parse a native GoLang version range into a set of constraints.
1037+ """
1038+ constraints = []
1039+
1040+ segments = string .split ("||" )
1041+ for segment in segments :
1042+
1043+ if not any (op in string for op in cls .vers_by_native_comparators ):
1044+ segment = "==" + segment
1045+
1046+ specifiers = SpecifierSet (segment )
1047+ for spec in specifiers :
1048+ operator = spec .operator
1049+ version = spec .version
1050+ version = cls .version_class (version )
1051+ comparator = cls .vers_by_native_comparators .get (operator , "=" )
1052+ constraint = VersionConstraint (comparator = comparator , version = version )
1053+ constraints .append (constraint )
1054+
1055+ return cls (constraints = constraints )
1056+
1057+ @classmethod
1058+ def from_natives (cls , strings ):
1059+ if isinstance (strings , str ):
1060+ return cls .from_native (strings )
1061+ constraints = []
1062+ for rel in strings :
1063+ constraints .extend (cls .from_native (rel ).constraints )
1064+ return cls (constraints = constraints )
1065+
9611066
9621067class GenericVersionRange (VersionRange ):
9631068 scheme = "generic"
0 commit comments