{-# 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)


-- <valid semver> ::= <version core>
--                  | <version core> "-" <pre-release>
--                  | <version core> "+" <build>
--                  | <version core> "-" <pre-release> "+" <build>
data SemanticVersion =
  SemanticVersionOnly Version
  | SemanticVersionPreRelease Version PreReleaseIdentifiers
  | SemanticVersionBuild Version BuildIdentifiers
  | SemanticVersionPreReleaseBuild Version PreReleaseIdentifiers BuildIdentifiers
  deriving (SemanticVersion -> SemanticVersion -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SemanticVersion -> SemanticVersion -> Bool
$c/= :: SemanticVersion -> SemanticVersion -> Bool
== :: SemanticVersion -> SemanticVersion -> Bool
$c== :: SemanticVersion -> SemanticVersion -> Bool
Eq, Int -> SemanticVersion -> ShowS
[SemanticVersion] -> ShowS
SemanticVersion -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SemanticVersion] -> ShowS
$cshowList :: [SemanticVersion] -> ShowS
show :: SemanticVersion -> String
$cshow :: SemanticVersion -> String
showsPrec :: Int -> SemanticVersion -> ShowS
$cshowsPrec :: Int -> SemanticVersion -> ShowS
Show)

class HasSemanticVersion a where
  semanticVersion ::
    Lens' a SemanticVersion

instance HasSemanticVersion SemanticVersion where
  semanticVersion :: Lens' SemanticVersion SemanticVersion
semanticVersion =
    forall a. a -> a
id

class AsSemanticVersion a where
  _SemanticVersion ::
    Prism' a SemanticVersion
  _SemanticVersionOnly ::
    Prism' a Version
  _SemanticVersionOnly =
    forall a. AsSemanticVersion a => Prism' a SemanticVersion
_SemanticVersion forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism'
      Version -> SemanticVersion
SemanticVersionOnly
      (\case
        SemanticVersionOnly Version
a ->
          forall a. a -> Maybe a
Just Version
a
        SemanticVersion
_ ->
          forall a. Maybe a
Nothing)
  _SemanticVersionPreRelease ::
    Prism' a (Version, PreReleaseIdentifiers)
  _SemanticVersionPreRelease =
    forall a. AsSemanticVersion a => Prism' a SemanticVersion
_SemanticVersion forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism'
      (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Version -> PreReleaseIdentifiers -> SemanticVersion
SemanticVersionPreRelease)
      (\case
        SemanticVersionPreRelease Version
v PreReleaseIdentifiers
pri ->
          forall a. a -> Maybe a
Just (Version
v, PreReleaseIdentifiers
pri)
        SemanticVersion
_ ->
          forall a. Maybe a
Nothing)
  _SemanticVersionBuild ::
    Prism' a (Version, BuildIdentifiers)
  _SemanticVersionBuild =
    forall a. AsSemanticVersion a => Prism' a SemanticVersion
_SemanticVersion forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism'
      (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Version -> BuildIdentifiers -> SemanticVersion
SemanticVersionBuild)
      (\case
        SemanticVersionBuild Version
v BuildIdentifiers
bi ->
          forall a. a -> Maybe a
Just (Version
v, BuildIdentifiers
bi)
        SemanticVersion
_ ->
          forall a. Maybe a
Nothing)
  _SemanticVersionPreReleaseBuild ::
    Prism' a (Version, PreReleaseIdentifiers, BuildIdentifiers)
  _SemanticVersionPreReleaseBuild =
    forall a. AsSemanticVersion a => Prism' a SemanticVersion
_SemanticVersion forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism'
      (\(Version
v, PreReleaseIdentifiers
pri, BuildIdentifiers
bi) -> Version
-> PreReleaseIdentifiers -> BuildIdentifiers -> SemanticVersion
SemanticVersionPreReleaseBuild Version
v PreReleaseIdentifiers
pri BuildIdentifiers
bi)
      (\case
        SemanticVersionPreReleaseBuild Version
v PreReleaseIdentifiers
pri BuildIdentifiers
bi ->
          forall a. a -> Maybe a
Just (Version
v, PreReleaseIdentifiers
pri, BuildIdentifiers
bi)
        SemanticVersion
_ ->
          forall a. Maybe a
Nothing)

instance AsSemanticVersion SemanticVersion where
  _SemanticVersion :: Prism' SemanticVersion SemanticVersion
_SemanticVersion =
    forall a. a -> a
id

instance HasVersion SemanticVersion where
  version :: Lens' SemanticVersion Version
version Version -> f Version
f (SemanticVersionOnly Version
v) =
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Version -> SemanticVersion
SemanticVersionOnly (Version -> f Version
f Version
v)
  version Version -> f Version
f (SemanticVersionPreRelease Version
v PreReleaseIdentifiers
pri) =
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Version -> PreReleaseIdentifiers -> SemanticVersion
`SemanticVersionPreRelease` PreReleaseIdentifiers
pri) (Version -> f Version
f Version
v)
  version Version -> f Version
f (SemanticVersionBuild Version
v BuildIdentifiers
bi) =
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Version -> BuildIdentifiers -> SemanticVersion
`SemanticVersionBuild` BuildIdentifiers
bi) (Version -> f Version
f Version
v)
  version Version -> f Version
f (SemanticVersionPreReleaseBuild Version
v PreReleaseIdentifiers
pri BuildIdentifiers
bi) =
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Version
v' -> Version
-> PreReleaseIdentifiers -> BuildIdentifiers -> SemanticVersion
SemanticVersionPreReleaseBuild Version
v' PreReleaseIdentifiers
pri BuildIdentifiers
bi) (Version -> f Version
f Version
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 :: forall (p :: * -> *). CharParsing p => p SemanticVersion
parseSemanticVersion =
  let parsePreRelease :: p PreReleaseIdentifiers
parsePreRelease =
        forall (m :: * -> *). CharParsing m => Char -> m Char
char Char
'-' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (p :: * -> *). CharParsing p => p PreReleaseIdentifiers
parsePreReleaseIdentifiers
      parseBuild :: p BuildIdentifiers
parseBuild =
        forall (m :: * -> *). CharParsing m => Char -> m Char
char Char
'+' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (p :: * -> *). CharParsing p => p BuildIdentifiers
parseBuildIdentifiers
      mkVersion :: Version
-> Maybe PreReleaseIdentifiers
-> Maybe BuildIdentifiers
-> SemanticVersion
mkVersion Version
v Maybe PreReleaseIdentifiers
Nothing Maybe BuildIdentifiers
Nothing =
        Version -> SemanticVersion
SemanticVersionOnly Version
v
      mkVersion Version
v (Just PreReleaseIdentifiers
pri) Maybe BuildIdentifiers
Nothing =
        Version -> PreReleaseIdentifiers -> SemanticVersion
SemanticVersionPreRelease Version
v PreReleaseIdentifiers
pri
      mkVersion Version
v Maybe PreReleaseIdentifiers
Nothing (Just BuildIdentifiers
bld) =
        Version -> BuildIdentifiers -> SemanticVersion
SemanticVersionBuild Version
v BuildIdentifiers
bld
      mkVersion Version
v (Just PreReleaseIdentifiers
pri) (Just BuildIdentifiers
bld) =
        Version
-> PreReleaseIdentifiers -> BuildIdentifiers -> SemanticVersion
SemanticVersionPreReleaseBuild Version
v PreReleaseIdentifiers
pri BuildIdentifiers
bld
  in  Version
-> Maybe PreReleaseIdentifiers
-> Maybe BuildIdentifiers
-> SemanticVersion
mkVersion forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (p :: * -> *). CharParsing p => p Version
parseVersion forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (m :: * -> *) a. Parsing m => m a -> m a
try (forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional p PreReleaseIdentifiers
parsePreRelease) forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (m :: * -> *) a. Parsing m => m a -> m a
try (forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional p BuildIdentifiers
parseBuild)