packages feed

semantic-version-0.0.1: src/Data/SemanticVersion/BuildIdentifier.hs

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE LambdaCase #-}

module Data.SemanticVersion.BuildIdentifier where

import Control.Applicative
import Control.Lens
import Data.Digit
import Data.List.NonEmpty
import Data.SemanticVersion.AlphanumericIdentifier
import Text.Parser.Char
import Text.Parser.Combinators

-- $setup
-- >>> import Text.Parsec(parse)
-- >>> import Data.Either(isLeft)

-- <build identifier> ::= <alphanumeric identifier>
--                      | <digits>
data BuildIdentifier =
  BuildIdentifierAlphanumeric AlphanumericIdentifier
  | BuildIdentifierDigits (NonEmpty DecDigit)
  deriving (Eq, Show)

class HasBuildIdentifier a where
  buildIdentifier ::
    Lens' a BuildIdentifier

instance HasBuildIdentifier BuildIdentifier where
  buildIdentifier =
    id

class AsBuildIdentifier a where
  _BuildIdentifier ::
    Prism' a BuildIdentifier
  _BuildIdentifierDigits ::
    Prism' a (NonEmpty DecDigit)
  _BuildIdentifierDigits =
    _BuildIdentifier .
    prism'
      BuildIdentifierDigits
      (\case
        BuildIdentifierDigits a ->
          Just a
        _ ->
          Nothing)

instance AsBuildIdentifier BuildIdentifier where
  _BuildIdentifier =
    id

instance AsAlphanumericIdentifier BuildIdentifier where
  _AlphanumericIdentifier =
    prism'
      BuildIdentifierAlphanumeric
      (\case
        BuildIdentifierAlphanumeric a ->
          Just a
        _ ->
          Nothing)

-- |
--
-- >>> parse (parseBuildIdentifier <* eof) "parseBuildIdentifier" "A"
-- Right (BuildIdentifierAlphanumeric (AlphanumericIdentifierNonDigit (NonDigitLetter (AlphaUpper Upper_A))))
--
-- >>> isLeft (parse parseBuildIdentifier "parseBuildIdentifier" "")
-- True
--
-- >>> parse (parseBuildIdentifier <* eof) "parseBuildIdentifier" "Abc-123--XYZ"
-- Right (BuildIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaUpper Upper_A)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_b)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_c)),IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterDigit DecDigit1,IdentifierCharacterDigit DecDigit2,IdentifierCharacterDigit DecDigit3,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_X)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_Y)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_Z))]))))
--
-- >>> isLeft (parse parseBuildIdentifier "parseBuildIdentifier" "+")
-- True
--
-- >>> parse parseBuildIdentifier "parseBuildIdentifier" "0"
-- Right (BuildIdentifierDigits (DecDigit0 :| []))
--
-- >>> parse parseBuildIdentifier "parseBuildIdentifier" "0+"
-- Right (BuildIdentifierDigits (DecDigit0 :| []))
--
-- >>> parse (parseBuildIdentifier <* eof) "parseBuildIdentifier" "0a"
-- Right (BuildIdentifierAlphanumeric (AlphanumericIdentifierCharacters (IdentifierCharacters (IdentifierCharacterDigit DecDigit0 :| [])) (NonDigitLetter (AlphaLower Lower_a))))
--
-- >>> parse parseBuildIdentifier "parseBuildIdentifier" "-"
-- Right (BuildIdentifierAlphanumeric (AlphanumericIdentifierNonDigit NonDigitHyphen))
--
-- >>> parse parseBuildIdentifier "parseBuildIdentifier" "Abc-123--XYZ+"
-- Right (BuildIdentifierAlphanumeric (AlphanumericIdentifierNonDigits (NonDigitLetter (AlphaUpper Upper_A)) (IdentifierCharacters (IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_b)) :| [IdentifierCharacterNonDigit (NonDigitLetter (AlphaLower Lower_c)),IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterDigit DecDigit1,IdentifierCharacterDigit DecDigit2,IdentifierCharacterDigit DecDigit3,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit NonDigitHyphen,IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_X)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_Y)),IdentifierCharacterNonDigit (NonDigitLetter (AlphaUpper Upper_Z))]))))
--
-- >>> parse parseBuildIdentifier "parseBuildIdentifier" "0901010"
-- Right (BuildIdentifierDigits (DecDigit0 :| [DecDigit9,DecDigit0,DecDigit1,DecDigit0,DecDigit1,DecDigit0]))
--
-- >>> parse parseBuildIdentifier "parseBuildIdentifier" "90109010"
-- Right (BuildIdentifierDigits (DecDigit9 :| [DecDigit0,DecDigit1,DecDigit0,DecDigit9,DecDigit0,DecDigit1,DecDigit0]))
parseBuildIdentifier ::
  CharParsing p =>
  p BuildIdentifier
parseBuildIdentifier =
  try (BuildIdentifierAlphanumeric <$> parseAlphanumericIdentifier) <|>
  BuildIdentifierDigits <$> some1 parseDecimal