{- | The RubyGems registry __wire__ JSON, decoded into a typed model.

A __placeholder boundary__ mirroring "Ecluse.Core.Registry.Pypi.Wire". Écluse serves
only npm, so this models just the one shape another part of the system reads from
RubyGems: the published version strings of the @\/api\/v1\/versions\/{gem}.json@
response, which is a JSON array with one entry per version. Only each entry's
@number@ (the version string) is modelled; the rest of the entry (platform, SHA,
timestamps) is ignored, leaving room for a full RubyGems adapter to grow the model
later.

Unlike the npm and PyPI listings, the document is a top-level array, so 'parseJSON'
decodes it as a list of 'VersionEntry'. An entry without a @number@ is a decode
failure rather than a silently-dropped element, since a version entry that names no
version is meaningless.
-}
module Ecluse.Core.Registry.Rubygems.Wire (
    VersionEntry (..),
    VersionListing (..),
    listingVersions,
) where

import Data.Aeson (FromJSON (parseJSON), withObject, (.:))

-- | One entry of the RubyGems versions array, modelled only by its version string.
newtype VersionEntry = VersionEntry
    { VersionEntry -> Text
veNumber :: Text
    -- ^ The version string (@number@), exactly as RubyGems lists it.
    }
    deriving stock (VersionEntry -> VersionEntry -> Bool
(VersionEntry -> VersionEntry -> Bool)
-> (VersionEntry -> VersionEntry -> Bool) -> Eq VersionEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VersionEntry -> VersionEntry -> Bool
== :: VersionEntry -> VersionEntry -> Bool
$c/= :: VersionEntry -> VersionEntry -> Bool
/= :: VersionEntry -> VersionEntry -> Bool
Eq, Int -> VersionEntry -> ShowS
[VersionEntry] -> ShowS
VersionEntry -> String
(Int -> VersionEntry -> ShowS)
-> (VersionEntry -> String)
-> ([VersionEntry] -> ShowS)
-> Show VersionEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VersionEntry -> ShowS
showsPrec :: Int -> VersionEntry -> ShowS
$cshow :: VersionEntry -> String
show :: VersionEntry -> String
$cshowList :: [VersionEntry] -> ShowS
showList :: [VersionEntry] -> ShowS
Show)

instance FromJSON VersionEntry where
    parseJSON :: Value -> Parser VersionEntry
parseJSON = String
-> (Object -> Parser VersionEntry) -> Value -> Parser VersionEntry
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"RubyGems version entry" ((Object -> Parser VersionEntry) -> Value -> Parser VersionEntry)
-> (Object -> Parser VersionEntry) -> Value -> Parser VersionEntry
forall a b. (a -> b) -> a -> b
$ \Object
o ->
        Text -> VersionEntry
VersionEntry (Text -> VersionEntry) -> Parser Text -> Parser VersionEntry
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"number"

-- | The whole @\/api\/v1\/versions\/{gem}.json@ array, one 'VersionEntry' per version.
newtype VersionListing = VersionListing
    { VersionListing -> [VersionEntry]
vlEntries :: [VersionEntry]
    -- ^ The version entries, in the order RubyGems returns them (newest first).
    }
    deriving stock (VersionListing -> VersionListing -> Bool
(VersionListing -> VersionListing -> Bool)
-> (VersionListing -> VersionListing -> Bool) -> Eq VersionListing
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VersionListing -> VersionListing -> Bool
== :: VersionListing -> VersionListing -> Bool
$c/= :: VersionListing -> VersionListing -> Bool
/= :: VersionListing -> VersionListing -> Bool
Eq, Int -> VersionListing -> ShowS
[VersionListing] -> ShowS
VersionListing -> String
(Int -> VersionListing -> ShowS)
-> (VersionListing -> String)
-> ([VersionListing] -> ShowS)
-> Show VersionListing
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VersionListing -> ShowS
showsPrec :: Int -> VersionListing -> ShowS
$cshow :: VersionListing -> String
show :: VersionListing -> String
$cshowList :: [VersionListing] -> ShowS
showList :: [VersionListing] -> ShowS
Show)

instance FromJSON VersionListing where
    parseJSON :: Value -> Parser VersionListing
parseJSON = ([VersionEntry] -> VersionListing)
-> Parser [VersionEntry] -> Parser VersionListing
forall a b. (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [VersionEntry] -> VersionListing
VersionListing (Parser [VersionEntry] -> Parser VersionListing)
-> (Value -> Parser [VersionEntry])
-> Value
-> Parser VersionListing
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Parser [VersionEntry]
forall a. FromJSON a => Value -> Parser a
parseJSON

{- | The published version strings of a gem: each entry's @number@, in the order
RubyGems returns them.
-}
listingVersions :: VersionListing -> [Text]
listingVersions :: VersionListing -> [Text]
listingVersions = (VersionEntry -> Text) -> [VersionEntry] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map VersionEntry -> Text
veNumber ([VersionEntry] -> [Text])
-> (VersionListing -> [VersionEntry]) -> VersionListing -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VersionListing -> [VersionEntry]
vlEntries