A µ-framework for representing, comparing, encoding and utilizing
semantic versions, eg. 1.2.3
or 2.0.0-beta
.
This is Version.swift
from the Swift Package Manager, with some minor
adjustments:
- More compact
Codable
implementation † - Implements
LosslessStringConvertible
‡ - Not a massive-single-source-file (MSSF)
- Online documentation
- Extensions for
Bundle
andProcessInfo
- Removal of the potentially fatal
ExpressibleByStringLiteral
conformance - A “tolerant” initializer for user input like
10.0
orv3
- Idiomatic implementations for
Range<Version>
- Initialization from
StringProtocol
, not justString
We have automatic monitoring for changes at Apple’s repo to alert us if we should need merge any fixes.
† Semantic versions can be losslessly expressed as strings; thus we do so.
‡ Like
Int
we can losslessly store a semantic version from a valid string, so we conform to the same protocol.
Hey there, I’m Max Howell. I’m a prolific producer of open source software and
probably you already use some of it (for example, I created brew
). I work
full-time on open source and it’s hard; currently I earn less than minimum
wage. Please help me continue my work, I appreciate it 🙏🏻
import Version
// these two initializers are the same, use whichever suits the code context
let v1 = Version(1,0,0)
let v2 = Version(major: 1, minor: 0, patch: 0)
let v3 = Version("1.2.3") // => 1.2.3: Version?
let v4 = Version(tolerant: "10.1") // => 10.1.0: Version?
let v5 = Version(tolerant: "10") // => 10.0.0: Version?
// a real Version object from your app’s Info.plist
let v6 = Bundle.main.version
let range = Version(1,2,3)..<Version(2,0,0)
let null: Version = .null // => Version(0,0,0)
let foo = Version(1,2,3) < Version(2,0,0) // => true
SwiftPM:
package.append(.package(url: "https://github.com/mxcl/Version.git", from: "2.0.0"))
Carthage:
Waiting on: @Carthage#1945.
Ranges work as you expect, but there are caveats for prerelease identifiers, here are the rules:
1.0.0..<2.0.0
does not include eg.2.0.0-alpha
This is probably what you expected. However:
1.0.0..<2.0.0
also does not include eg.1.5.0-alpha
However:
1.0.0..<2.0.0-beta
does include eg.2.0.0-alpha
This is how the majority of Semantic Version libraries work.
Both comparable and equatable ignore build metadata as per the specification. Thus:
Version("1.2.3+14") == Version("1.2.3+15") // => true
Version("1.2.3+14") <= Version("1.2.3+15") // => true
Version("1.2.3+14") < Version("1.2.3+15") // => false
This also means that Hashable
must mirror this behavior, thus:
dict[Version("1.2.3+14")] = 1
dict[Version("1.2.3+15")] = 2
dict.count // => 1
dict // => ["1.2.3+15": 2]
Be aware of this as it may catch you out, naturally this will also effect structures
that depend on Hashable
, eg. Set
.