@@ -11,73 +11,74 @@ final class VersionHelpers {
1111 /// Returns `orderedDescending` if the lhs version is newer than the rhs
1212 ///
1313 static func compare( _ lhs: String , _ rhs: String ) -> ComparisonResult {
14+ let leftComponents = versionComponents ( of: lhs)
15+ let rightComponents = versionComponents ( of: rhs)
16+ let maxComponents = max ( leftComponents. count, rightComponents. count)
1417
15- /// Replace _ - and + with a .
16- ///
17- func replaceUnderscoreDashAndPlusWithDot( _ string: String ) -> String {
18- string. replacingOccurrences ( of: " ([_ \\ -+]+) " , with: " . " , options: . regularExpression)
19- }
18+ for index in 0 ..< maxComponents {
19+ /// Treat missing components (e.g. 1.2 being compared to 1.1.3 as "0", i.e. 1.2.0)
20+ let leftComponent = index < leftComponents. count ? leftComponents [ index] : " 0 "
21+ let rightComponent = index < rightComponents. count ? rightComponents [ index] : " 0 "
2022
21- /// Insert a . before and after any non number
22- ///
23- func insertDotsBeforeAndAfterAnyNonNumber ( _ string : String ) -> String {
24- string . replacingOccurrences ( of : " ([^0-9.]+) " , with : " .$1. " , options : . regularExpression )
23+ let comparisonResult = compareStringComponents ( leftComponent , rightComponent )
24+ if comparisonResult != . orderedSame {
25+ return comparisonResult
26+ }
2527 }
2628
27- /// Score and compare two string components
28- ///
29- func compareStringComponents( _ lhs: String , _ rhs: String ) -> ComparisonResult {
30- /// Score each component
31- let lhsScore = VersionComponentScore ( from: lhs)
32- let rhsScore = VersionComponentScore ( from: rhs)
33-
34- if lhsScore < rhsScore {
35- return . orderedAscending
36- }
29+ return . orderedSame
30+ }
31+ }
3732
38- if lhsScore > rhsScore {
39- return . orderedDescending
40- }
33+ // MARK: - Private Helpers
34+ //
35+ private extension VersionHelpers {
36+ /// Replace _ - and + with a .
37+ ///
38+ static func replaceUnderscoreDashAndPlusWithDot( _ string: String ) -> String {
39+ string. replacingOccurrences ( of: " ([_ \\ -+]+) " , with: " . " , options: . regularExpression)
40+ }
4141
42- if lhsScore == . number && rhsScore == . number {
43- let lhsAsNumber = NSNumber ( value: Int ( lhs) ?? 0 )
44- let rhsAsNumber = NSNumber ( value: Int ( rhs) ?? 0 )
42+ /// Insert a . before and after any non number
43+ ///
44+ static func insertDotsBeforeAndAfterAnyNonNumber( _ string: String ) -> String {
45+ string. replacingOccurrences ( of: " ([^0-9.]+) " , with: " .$1. " , options: . regularExpression)
46+ }
4547
46- let comparisonResult = lhsAsNumber . compare ( rhsAsNumber )
47- if comparisonResult != . orderedSame {
48- return comparisonResult
49- }
50- }
48+ /// Score and compare two string components
49+ ///
50+ static func compareStringComponents ( _ lhs : String , _ rhs : String ) -> ComparisonResult {
51+ let lhsScore = VersionComponentScore ( from : lhs )
52+ let rhsScore = VersionComponentScore ( from : rhs )
5153
52- return . orderedSame
54+ if lhsScore < rhsScore {
55+ return . orderedAscending
5356 }
5457
55- /// Process the given string into version components
56- ///
57- func versionComponents( of string: String ) -> [ String ] {
58- var stringToComponentize = replaceUnderscoreDashAndPlusWithDot ( string)
59- stringToComponentize = insertDotsBeforeAndAfterAnyNonNumber ( stringToComponentize)
60- return stringToComponentize. components ( separatedBy: " . " )
58+ if lhsScore > rhsScore {
59+ return . orderedDescending
6160 }
6261
63- let leftComponents = versionComponents ( of: lhs)
64- let rightComponents = versionComponents ( of: rhs)
65-
66- let maxComponents = max ( leftComponents. count, rightComponents. count)
62+ if lhsScore == . number && rhsScore == . number {
63+ let lhsAsNumber = NSNumber ( value: Int ( lhs) ?? 0 )
64+ let rhsAsNumber = NSNumber ( value: Int ( rhs) ?? 0 )
6765
68- for index in 0 ..< maxComponents {
69- /// Treat missing components (e.g. 1.2 being compared to 1.1.3 as "0", i.e. 1.2.0
70- let leftComponent = index < leftComponents. count ? leftComponents [ index] : " 0 "
71- let rightComponent = index < rightComponents. count ? rightComponents [ index] : " 0 "
72-
73- let comparisonResult = compareStringComponents ( leftComponent, rightComponent)
66+ let comparisonResult = lhsAsNumber. compare ( rhsAsNumber)
7467 if comparisonResult != . orderedSame {
7568 return comparisonResult
7669 }
7770 }
7871
7972 return . orderedSame
8073 }
74+
75+ /// Process the given string into version components
76+ ///
77+ static func versionComponents( of string: String ) -> [ String ] {
78+ var stringToComponentize = replaceUnderscoreDashAndPlusWithDot ( string)
79+ stringToComponentize = insertDotsBeforeAndAfterAnyNonNumber ( stringToComponentize)
80+ return stringToComponentize. components ( separatedBy: " . " )
81+ }
8182}
8283
8384/// Defines the score (rank) of a component string within a version string.
@@ -89,7 +90,7 @@ final class VersionHelpers {
8990///
9091/// Ranked per https://www.php.net/manual/en/function.version-compare.php
9192///
92- fileprivate enum VersionComponentScore : Comparable {
93+ private enum VersionComponentScore : Comparable {
9394 case other
9495 case dev
9596 case alpha
@@ -99,7 +100,7 @@ fileprivate enum VersionComponentScore: Comparable {
99100 case patch
100101}
101102
102- fileprivate extension VersionComponentScore {
103+ private extension VersionComponentScore {
103104 init ( from: String ) {
104105 if from == " dev " {
105106 self = . dev
0 commit comments