Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
# https://github.com/actions/virtual-environments
os: [macos-12, ubuntu-20.04]
os: [macos-13, ubuntu-24.04]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand All @@ -23,8 +23,8 @@ jobs:
run-tests:
strategy:
matrix:
swift-version: ['5.6', '5.7', '5.8', '5.9', '5.10']
runs-on: ubuntu-20.04
swift-version: ['5.10', '6.0', '6.1']
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: fwal/setup-swift@v2
Expand Down
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import PackageDescription

let package = Package(
name: "SemanticVersion",
platforms: [.macOS("13.0")],
products: [
.library(
name: "SemanticVersion",
Expand Down
48 changes: 0 additions & 48 deletions Sources/SemanticVersion/NSRegularExpression+ext.swift

This file was deleted.

4 changes: 4 additions & 0 deletions Sources/SemanticVersion/SemanticVersion+Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#if canImport(Foundation)

import Foundation

public enum SemanticVersionStrategy {
Expand Down Expand Up @@ -100,3 +102,5 @@ extension SemanticVersion: Codable {
}
}
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


extension SemanticVersion: LosslessStringConvertible {

/// Initialize a version from a string. Returns `nil` if the string is not a semantic version.
/// - Parameter string: Version string.
public init?(_ string: String) {
guard let match = string.wholeMatch(of: semVerRegex) else { return nil }
guard
let major = Int(match.major),
let minor = Int(match.minor),
let patch = Int(match.patch)
else { return nil }
self = .init(major, minor, patch,
match.prerelease.map(String.init) ?? "",
match.buildmetadata.map(String.init) ?? "")
}

public var description: String {
let pre = preRelease.isEmpty ? "" : "-" + preRelease
let bld = build.isEmpty ? "" : "+" + build
return "\(major).\(minor).\(patch)\(pre)\(bld)"
}
}


// Source: https://regex101.com/r/Ly7O1x/3/
// Linked from https://semver.org
let semVerRegex = #/
^
v? # SPI extension: allow leading 'v'
(?<major>0|[1-9]\d*)
\.
(?<minor>0|[1-9]\d*)
\.
(?<patch>0|[1-9]\d*)
(?:-
(?<prerelease>
(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
(?:\.
(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
)
*)
)?
(?:\+
(?<buildmetadata>[0-9a-zA-Z-]+
(?:\.[0-9a-zA-Z-]+)
*)
)?
$
/#
99 changes: 18 additions & 81 deletions Sources/SemanticVersion/SemanticVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation


/// `SemanticVersion` is a struct representing a software or project version according to ["Semantic Versioning"](https://semver.org).
///
Expand Down Expand Up @@ -50,28 +48,6 @@ public struct SemanticVersion: Equatable, Hashable {
}
}

extension SemanticVersion: LosslessStringConvertible {

/// Initialize a version from a string. Returns `nil` if the string is not a semantic version.
/// - Parameter string: Version string.
public init?(_ string: String) {
let groups = semVerRegex.matchGroups(string)
guard
groups.count == semVerRegex.numberOfCaptureGroups,
let major = Int(groups[0]),
let minor = Int(groups[1]),
let patch = Int(groups[2])
else { return nil }
self = .init(major, minor, patch, groups[3], groups[4])
}

public var description: String {
let pre = preRelease.isEmpty ? "" : "-" + preRelease
let bld = build.isEmpty ? "" : "+" + build
return "\(major).\(minor).\(patch)\(pre)\(bld)"
}
}


extension SemanticVersion: Comparable {
public static func < (lhs: SemanticVersion, rhs: SemanticVersion) -> Bool {
Expand Down Expand Up @@ -140,7 +116,8 @@ extension SemanticVersion.PreReleaseIdentifier: Comparable {
}


extension Array: Comparable where Element == SemanticVersion.PreReleaseIdentifier {
#if compiler(>=6)
extension Array: @retroactive Comparable where Element == SemanticVersion.PreReleaseIdentifier {
public static func < (lhs: Self, rhs: Self) -> Bool {
// Per section 11.4 of the semver spec, compare left to right until a
// difference is found.
Expand All @@ -154,64 +131,24 @@ extension Array: Comparable where Element == SemanticVersion.PreReleaseIdentifie
return lhs.count < rhs.count
}
}
#else
extension Array: Comparable where Element == SemanticVersion.PreReleaseIdentifier {
public static func < (lhs: Self, rhs: Self) -> Bool {
// Per section 11.4 of the semver spec, compare left to right until a
// difference is found.
// See: https://semver.org/#spec-item-11
for (lhIdentifier, rhIdentifier) in zip(lhs, rhs) {
if lhIdentifier != rhIdentifier { return lhIdentifier < rhIdentifier }
}

#if swift(>=5.5)
extension SemanticVersion: Sendable {}
// 11.4.4 - A larger set of identifiers will have a higher precendence
// than a smaller set, if all the preceding identifiers are equal.
return lhs.count < rhs.count
}
}
#endif


// Source: https://regex101.com/r/Ly7O1x/3/
// Linked from https://semver.org
#if swift(>=5)

let semVerRegex = NSRegularExpression(#"""
^
v? # SPI extension: allow leading 'v'
(?<major>0|[1-9]\d*)
\.
(?<minor>0|[1-9]\d*)
\.
(?<patch>0|[1-9]\d*)
(?:-
(?<prerelease>
(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
(?:\.
(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
)
*)
)?
(?:\+
(?<buildmetadata>[0-9a-zA-Z-]+
(?:\.[0-9a-zA-Z-]+)
*)
)?
$
"""#, options: [.allowCommentsAndWhitespace])

#else

let semVerRegex = NSRegularExpression("""
^
v? # SPI extension: allow leading 'v'
(?<major>0|[1-9]\\d*)
\\.
(?<minor>0|[1-9]\\d*)
\\.
(?<patch>0|[1-9]\\d*)
(?:-
(?<prerelease>
(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)
(?:\\.
(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)
)
*)
)?
(?:\\+
(?<buildmetadata>[0-9a-zA-Z-]+
(?:\\.[0-9a-zA-Z-]+)
*)
)?
$
""", options: [.allowCommentsAndWhitespace])

#if swift(>=5.5)
extension SemanticVersion: Sendable {}
#endif
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
// Copyright Dave Verwer, Sven A. Schmidt, and other contributors.
//
// SemanticVersionCodingTests.swift
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// Created by Chris Eplett on 11/3/23.
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#if canImport(Foundation)

import XCTest

import SemanticVersion

final class SemanticVersionCodingTests: XCTestCase {
final class SemanticVersionCodableTests: XCTestCase {
func test_defaultCodable_is_default() throws {
XCTAssertEqual(.defaultCodable, JSONEncoder().semanticVersionEncodingStrategy)
XCTAssertEqual(.defaultCodable, JSONDecoder().semanticVersionDecodingStrategy)
Expand Down Expand Up @@ -191,3 +200,5 @@ final class SemanticVersionCodingTests: XCTestCase {
}
}
}

#endif
Loading