@@ -27,13 +27,89 @@ class Dependency extends Location {
2727 /**
2828 * Gets the version of the dependency.
2929 */
30- string getVersion ( ) { result = version . replaceAll ( "=" , "" ) }
30+ string getVersion ( ) { result = this . getSemanticVersion ( ) . getPretty ( ) }
3131
32- SemanticVersion getSemanticVersion ( ) { result = this .getVersion ( ) }
32+ /**
33+ * Gets the raw version of the dependency.
34+ */
35+ string getRawVersion ( ) { result = version }
36+
37+ /**
38+ * Gets the semantic version of the dependency.
39+ */
40+ SemanticVersion getSemanticVersion ( ) { result = version }
3341}
3442
3543class SemanticVersion extends string {
36- private Dependency dep ;
44+ Dependency dep ;
45+ string normalized ;
46+ string pretty ;
47+
48+ SemanticVersion ( ) {
49+ this = dep .getRawVersion ( ) and
50+ normalized = normalizeSemver ( this ) and
51+ pretty = prettySemver ( this )
52+ }
53+
54+ /**
55+ * Holds if this version may be before `last`.
56+ */
57+ bindingset [ last]
58+ predicate maybeBefore ( string last ) { normalized < normalizeSemver ( last ) }
59+
60+ /**
61+ * Holds if this version may be after `first`.
62+ */
63+ bindingset [ first]
64+ predicate maybeAfter ( string first ) { normalizeSemver ( first ) < normalized }
3765
38- SemanticVersion ( ) { this = dep .getVersion ( ) }
66+ /**
67+ * Holds if this version may be between `first` (inclusive) and `last` (exclusive).
68+ */
69+ bindingset [ first, last]
70+ predicate maybeBetween ( string first , string last ) {
71+ normalizeSemver ( first ) <= normalized and
72+ normalized < normalizeSemver ( last )
73+ }
74+
75+ /**
76+ * Holds if this version is equivalent to `other`.
77+ */
78+ bindingset [ other]
79+ predicate is ( string other ) { normalized = normalizeSemver ( other ) }
80+
81+ string getPretty ( ) { result = pretty }
3982}
83+
84+ bindingset [ str]
85+ private string leftPad ( string str ) { result = ( "000" + str ) .suffix ( str .length ( ) ) }
86+
87+ /**
88+ * Normalizes a SemVer string such that the lexicographical ordering
89+ * of two normalized strings is consistent with the SemVer ordering.
90+ *
91+ * Pre-release information and build metadata is not yet supported.
92+ */
93+ bindingset [ orig]
94+ private string normalizeSemver ( string orig ) {
95+ exists ( string pattern , string major , string minor , string patch |
96+ pattern = "(=|~>|^)(\\d+)\\.(\\d+)\\.(\\d+)" and
97+ major = orig .regexpCapture ( pattern , 2 ) and
98+ minor = orig .regexpCapture ( pattern , 3 ) and
99+ patch = orig .regexpCapture ( pattern , 4 )
100+ |
101+ result = leftPad ( major ) + "." + leftPad ( minor ) + "." + leftPad ( patch )
102+ )
103+ }
104+
105+ bindingset [ orig]
106+ private string prettySemver ( string orig ) {
107+ exists ( string pattern , string major , string minor , string patch |
108+ pattern = "(=|~>|^)(\\d+)\\.(\\d+)\\.(\\d+)" and
109+ major = orig .regexpCapture ( pattern , 2 ) and
110+ minor = orig .regexpCapture ( pattern , 3 ) and
111+ patch = orig .regexpCapture ( pattern , 4 )
112+ |
113+ result = major + "." + minor + "." + patch
114+ )
115+ }
0 commit comments