{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE LambdaCase #-} module Data.SemanticVersion.SemanticVersion where import Control.Lens import Data.SemanticVersion.BuildIdentifiers import Data.SemanticVersion.PreReleaseIdentifiers import Data.SemanticVersion.Version import Text.Parser.Char import Text.Parser.Combinators -- $setup -- >>> import Text.Parsec(parse) -- >>> import Data.Either(isLeft) -- ::= -- | "-" -- | "+" -- | "-" "+" data SemanticVersion = SemanticVersionOnly Version | SemanticVersionPreRelease Version PreReleaseIdentifiers | SemanticVersionBuild Version BuildIdentifiers | SemanticVersionPreReleaseBuild Version PreReleaseIdentifiers BuildIdentifiers deriving (Eq, Show) class HasSemanticVersion a where semanticVersion :: Lens' a SemanticVersion instance HasSemanticVersion SemanticVersion where semanticVersion = id class AsSemanticVersion a where _SemanticVersion :: Prism' a SemanticVersion _SemanticVersionOnly :: Prism' a Version _SemanticVersionOnly = _SemanticVersion . prism' SemanticVersionOnly (\case SemanticVersionOnly a -> Just a _ -> Nothing) _SemanticVersionPreRelease :: Prism' a (Version, PreReleaseIdentifiers) _SemanticVersionPreRelease = _SemanticVersion . prism' (uncurry SemanticVersionPreRelease) (\case SemanticVersionPreRelease v pri -> Just (v, pri) _ -> Nothing) _SemanticVersionBuild :: Prism' a (Version, BuildIdentifiers) _SemanticVersionBuild = _SemanticVersion . prism' (uncurry SemanticVersionBuild) (\case SemanticVersionBuild v bi -> Just (v, bi) _ -> Nothing) _SemanticVersionPreReleaseBuild :: Prism' a (Version, PreReleaseIdentifiers, BuildIdentifiers) _SemanticVersionPreReleaseBuild = _SemanticVersion . prism' (\(v, pri, bi) -> SemanticVersionPreReleaseBuild v pri bi) (\case SemanticVersionPreReleaseBuild v pri bi -> Just (v, pri, bi) _ -> Nothing) instance AsSemanticVersion SemanticVersion where _SemanticVersion = id instance HasVersion SemanticVersion where version f (SemanticVersionOnly v) = fmap SemanticVersionOnly (f v) version f (SemanticVersionPreRelease v pri) = fmap (`SemanticVersionPreRelease` pri) (f v) version f (SemanticVersionBuild v bi) = fmap (`SemanticVersionBuild` bi) (f v) version f (SemanticVersionPreReleaseBuild v pri bi) = fmap (\v' -> SemanticVersionPreReleaseBuild v' pri bi) (f v) -- | -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "0.0.0" -- Right (SemanticVersion (Version NumericIdentifierZero NumericIdentifierZero NumericIdentifierZero)) -- -- >>> isLeft (parse parseSemanticVersion "parseSemanticVersion" "") -- True -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.2.3" -- Right (SemanticVersion (Version (NumericIdentifierDigits DecDigitNoZero1 []) (NumericIdentifierDigits DecDigitNoZero2 []) (NumericIdentifierDigits DecDigitNoZero3 []))) -- -- >>> isLeft(parse parseSemanticVersion "parseSemanticVersion" "01.2.3") -- True -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "10.2.3" -- Right (SemanticVersion (Version (NumericIdentifierDigits DecDigitNoZero1 [DecDigit0]) (NumericIdentifierDigits DecDigitNoZero2 []) (NumericIdentifierDigits DecDigitNoZero3 []))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "38012.5.6" -- Right (SemanticVersion (Version (NumericIdentifierDigits DecDigitNoZero3 [DecDigit8,DecDigit0,DecDigit1,DecDigit2]) (NumericIdentifierDigits DecDigitNoZero5 []) (NumericIdentifierDigits DecDigitNoZero6 []))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "38012.5.5432" -- Right (SemanticVersion (Version (NumericIdentifierDigits DecDigitNoZero3 [DecDigit8,DecDigit0,DecDigit1,DecDigit2]) (NumericIdentifierDigits DecDigitNoZero5 []) (NumericIdentifierDigits DecDigitNoZero5 [DecDigit4,DecDigit3,DecDigit2]))) -- -- >>> isLeft (parse (parseSemanticVersion <* eof) "parseSemanticVersion" "38012.05.5432") -- True -- -- >>> isLeft (parse (parseSemanticVersion <* eof) "parseSemanticVersion" "38012.5.05432") -- True -- -- >>> isLeft (parse parseSemanticVersion "parseSemanticVersion" "a") -- True -- -- >>> isLeft (parse parseSemanticVersion "parseSemanticVersion" "-") -- True -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-alpha" -- Right (SemanticVersionPreRelease (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_a)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_l)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_p)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_h)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_a))]))) :| []))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-alpha.1" -- Right (SemanticVersionPreRelease (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_a)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_l)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_p)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_h)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_a))]))) :| [PreReleaseIdentifierNumeric (NumericIdentifierDigits DecDigitNoZero1 [])]))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-0.3.7" -- Right (SemanticVersionPreRelease (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierNumeric NumericIdentifierZero :| [PreReleaseIdentifierNumeric (NumericIdentifierDigits DecDigitNoZero3 []),PreReleaseIdentifierNumeric (NumericIdentifierDigits DecDigitNoZero7 [])]))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-x.7.z.92" -- Right (SemanticVersionPreRelease (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigit (NonDigitLetter (AlphaLower Lower_x))) :| [PreReleaseIdentifierNumeric (NumericIdentifierDigits DecDigitNoZero7 []),PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigit (NonDigitLetter (AlphaLower Lower_z))),PreReleaseIdentifierNumeric (NumericIdentifierDigits DecDigitNoZero9 [DecDigit2])]))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-x-y-z.--" -- Right (SemanticVersionPreRelease (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_x)) (IdentifierCharacters (IdentifierCharacterNonDigit NonDigitHyphen :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_y)),IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_z))]))) :| [PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigits NonDigitHyphen (IdentifierCharacters (IdentifierCharacterNonDigit NonDigitHyphen :| [])))]))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-alpha+001" -- Right (SemanticVersionPreReleaseBuild (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_a)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_l)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_p)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_h)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_a))]))) :| [])) (BuildIdentifiers (BuildIdentifierDigits (DecDigit0 :| [DecDigit0,DecDigit1]) :| []))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0+20130313144700" -- Right (SemanticVersionBuild (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (BuildIdentifiers (BuildIdentifierDigits (DecDigit2 :| [DecDigit0,DecDigit1,DecDigit3,DecDigit0,DecDigit3,DecDigit1,DecDigit3,DecDigit1,DecDigit4,DecDigit4,DecDigit7,DecDigit0,DecDigit0]) :| []))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0-beta+exp.sha.5114f85" -- Right (SemanticVersionPreReleaseBuild (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (PreReleaseIdentifiers (PreReleaseIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_b)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_e)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_t)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_a))]))) :| [])) (BuildIdentifiers (BuildIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_e)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_x)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_p))]))) :| [BuildIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaLower Lower_s)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_h)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_a))]))),BuildIdentifierAlphanumeric (AlphanumericIdentifierCharacters2 (IdentifierCharacters (IdentifierCharacterDigit DecDigit5 :| [IdentifierCharacterDigit DecDigit1,IdentifierCharacterDigit DecDigit1,IdentifierCharacterDigit DecDigit4])) (NonDigitLetter (AlphaLower Lower_f)) (IdentifierCharacters (IdentifierCharacterDigit DecDigit8 :| [IdentifierCharacterDigit DecDigit5])))]))) -- -- >>> parse (parseSemanticVersion <* eof) "parseSemanticVersion" "1.0.0+21AF26D3----117B344092BD" -- Right (SemanticVersionBuild (Version (NumericIdentifierDigits DecDigitNoZero1 []) NumericIdentifierZero NumericIdentifierZero) (BuildIdentifiers (BuildIdentifierAlphanumeric (AlphanumericIdentifierCharacters2 (IdentifierCharacters (IdentifierCharacterDigit DecDigit2 :| [IdentifierCharacterDigit DecDigit1])) (NonDigitLetter (AlphaUpper Upper_A)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_F)) :| [IdentifierCharacterDigit DecDigit2,IdentifierCharacterDigit DecDigit6,IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_D)),IdentifierCharacterDigit DecDigit3,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterDigit DecDigit1,IdentifierCharacterDigit DecDigit1,IdentifierCharacterDigit DecDigit7,IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_B)),IdentifierCharacterDigit DecDigit3,IdentifierCharacterDigit DecDigit4,IdentifierCharacterDigit DecDigit4,IdentifierCharacterDigit DecDigit0,IdentifierCharacterDigit DecDigit9,IdentifierCharacterDigit DecDigit2,IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_B)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_D))]))) :| []))) parseSemanticVersion :: CharParsing p => p SemanticVersion parseSemanticVersion = let parsePreRelease = char '-' *> parsePreReleaseIdentifiers parseBuild = char '+' *> parseBuildIdentifiers mkVersion v Nothing Nothing = SemanticVersionOnly v mkVersion v (Just pri) Nothing = SemanticVersionPreRelease v pri mkVersion v Nothing (Just bld) = SemanticVersionBuild v bld mkVersion v (Just pri) (Just bld) = SemanticVersionPreReleaseBuild v pri bld in mkVersion <$> parseVersion <*> try (optional parsePreRelease) <*> try (optional parseBuild)