module Ecluse.Core.Registry.Npm.SelectiveDecode (
SelectedVersion (..),
SelectiveError (..),
selectVersionFromPackument,
) where
import Data.Aeson (Value)
import Data.Aeson.Decoding.ByteString (bsToTokens)
import Data.Aeson.Decoding.Tokens (TkRecord (..), Tokens (TkRecordOpen))
import Data.Aeson.Key qualified as Key
import Ecluse.Core.Json.Selective (
SelectiveError (..),
findInRecord,
materialiseWithinBudget,
skipValue,
trailingWhitespace,
withRecord,
)
import Ecluse.Core.Version (Version, renderVersion)
data SelectedVersion = SelectedVersion
{ SelectedVersion -> Maybe Value
svName :: Maybe Value
, SelectedVersion -> Maybe Value
svVersion :: Maybe Value
, SelectedVersion -> Maybe Value
svTime :: Maybe Value
, SelectedVersion -> Int
svVersionCount :: Int
}
deriving stock (SelectedVersion -> SelectedVersion -> Bool
(SelectedVersion -> SelectedVersion -> Bool)
-> (SelectedVersion -> SelectedVersion -> Bool)
-> Eq SelectedVersion
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SelectedVersion -> SelectedVersion -> Bool
== :: SelectedVersion -> SelectedVersion -> Bool
$c/= :: SelectedVersion -> SelectedVersion -> Bool
/= :: SelectedVersion -> SelectedVersion -> Bool
Eq, Int -> SelectedVersion -> ShowS
[SelectedVersion] -> ShowS
SelectedVersion -> String
(Int -> SelectedVersion -> ShowS)
-> (SelectedVersion -> String)
-> ([SelectedVersion] -> ShowS)
-> Show SelectedVersion
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SelectedVersion -> ShowS
showsPrec :: Int -> SelectedVersion -> ShowS
$cshow :: SelectedVersion -> String
show :: SelectedVersion -> String
$cshowList :: [SelectedVersion] -> ShowS
showList :: [SelectedVersion] -> ShowS
Show)
selectVersionFromPackument :: Int -> Version -> ByteString -> Either SelectiveError SelectedVersion
selectVersionFromPackument :: Int
-> Version -> ByteString -> Either SelectiveError SelectedVersion
selectVersionFromPackument Int
maxDepth Version
version ByteString
body
| Int
maxDepth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 = SelectiveError -> Either SelectiveError SelectedVersion
forall a b. a -> Either a b
Left SelectiveError
SelectiveTooDeeplyNested
| Bool
otherwise = case ByteString -> Tokens ByteString String
bsToTokens ByteString
body of
TkRecordOpen TkRecord ByteString String
rec -> Int
-> Text
-> TkRecord ByteString String
-> Either SelectiveError SelectedVersion
walkTop (Int
maxDepth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Version -> Text
renderVersion Version
version) TkRecord ByteString String
rec
Tokens ByteString String
_ -> SelectiveError -> Either SelectiveError SelectedVersion
forall a b. a -> Either a b
Left SelectiveError
SelectiveUndecodable
emptySelection :: SelectedVersion
emptySelection :: SelectedVersion
emptySelection = Maybe Value -> Maybe Value -> Maybe Value -> Int -> SelectedVersion
SelectedVersion Maybe Value
forall a. Maybe a
Nothing Maybe Value
forall a. Maybe a
Nothing Maybe Value
forall a. Maybe a
Nothing Int
0
data WalkState = WalkState
{ WalkState -> SelectedVersion
wsSelection :: SelectedVersion
, WalkState -> Bool
wsSeenName :: Bool
, WalkState -> Bool
wsSeenVersions :: Bool
, WalkState -> Bool
wsSeenTime :: Bool
}
initialWalk :: WalkState
initialWalk :: WalkState
initialWalk = SelectedVersion -> Bool -> Bool -> Bool -> WalkState
WalkState SelectedVersion
emptySelection Bool
False Bool
False Bool
False
walkTop :: Int -> Text -> TkRecord ByteString String -> Either SelectiveError SelectedVersion
walkTop :: Int
-> Text
-> TkRecord ByteString String
-> Either SelectiveError SelectedVersion
walkTop Int
childBudget Text
target = (WalkState -> SelectedVersion)
-> Either SelectiveError WalkState
-> Either SelectiveError SelectedVersion
forall a b.
(a -> b) -> Either SelectiveError a -> Either SelectiveError b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap WalkState -> SelectedVersion
wsSelection (Either SelectiveError WalkState
-> Either SelectiveError SelectedVersion)
-> (TkRecord ByteString String -> Either SelectiveError WalkState)
-> TkRecord ByteString String
-> Either SelectiveError SelectedVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WalkState
-> TkRecord ByteString String -> Either SelectiveError WalkState
go WalkState
initialWalk
where
go :: WalkState
-> TkRecord ByteString String -> Either SelectiveError WalkState
go WalkState
st = \case
TkRecordEnd ByteString
leftover
| ByteString -> Bool
trailingWhitespace ByteString
leftover -> WalkState -> Either SelectiveError WalkState
forall a b. b -> Either a b
Right WalkState
st
| Bool
otherwise -> SelectiveError -> Either SelectiveError WalkState
forall a b. a -> Either a b
Left SelectiveError
SelectiveUndecodable
TkRecordErr String
_ -> SelectiveError -> Either SelectiveError WalkState
forall a b. a -> Either a b
Left SelectiveError
SelectiveUndecodable
TkPair Key
key Tokens (TkRecord ByteString String) String
valueToks -> case Key -> Text
Key.toText Key
key of
Text
"versions" -> (WalkState -> Bool)
-> (WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String))
-> WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError WalkState
adoptFirst WalkState -> Bool
wsSeenVersions WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String)
forall {b}.
WalkState
-> Tokens b String -> Either SelectiveError (WalkState, b)
captureVersions WalkState
st Tokens (TkRecord ByteString String) String
valueToks
Text
"time" -> (WalkState -> Bool)
-> (WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String))
-> WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError WalkState
adoptFirst WalkState -> Bool
wsSeenTime WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String)
forall {b}.
WalkState
-> Tokens b String -> Either SelectiveError (WalkState, b)
captureTime WalkState
st Tokens (TkRecord ByteString String) String
valueToks
Text
"name" -> (WalkState -> Bool)
-> (WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String))
-> WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError WalkState
adoptFirst WalkState -> Bool
wsSeenName WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String)
forall {b}.
WalkState
-> Tokens b String -> Either SelectiveError (WalkState, b)
captureName WalkState
st Tokens (TkRecord ByteString String) String
valueToks
Text
_ -> Int
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (TkRecord ByteString String)
forall k. Int -> Tokens k String -> Either SelectiveError k
skipValue Int
childBudget Tokens (TkRecord ByteString String) String
valueToks Either SelectiveError (TkRecord ByteString String)
-> (TkRecord ByteString String -> Either SelectiveError WalkState)
-> Either SelectiveError WalkState
forall a b.
Either SelectiveError a
-> (a -> Either SelectiveError b) -> Either SelectiveError b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= WalkState
-> TkRecord ByteString String -> Either SelectiveError WalkState
go WalkState
st
adoptFirst :: (WalkState -> Bool)
-> (WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String))
-> WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError WalkState
adoptFirst WalkState -> Bool
captured WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String)
capture WalkState
st Tokens (TkRecord ByteString String) String
valueToks
| WalkState -> Bool
captured WalkState
st = Int
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (TkRecord ByteString String)
forall k. Int -> Tokens k String -> Either SelectiveError k
skipValue Int
childBudget Tokens (TkRecord ByteString String) String
valueToks Either SelectiveError (TkRecord ByteString String)
-> (TkRecord ByteString String -> Either SelectiveError WalkState)
-> Either SelectiveError WalkState
forall a b.
Either SelectiveError a
-> (a -> Either SelectiveError b) -> Either SelectiveError b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= WalkState
-> TkRecord ByteString String -> Either SelectiveError WalkState
go WalkState
st
| Bool
otherwise = WalkState
-> Tokens (TkRecord ByteString String) String
-> Either SelectiveError (WalkState, TkRecord ByteString String)
capture WalkState
st Tokens (TkRecord ByteString String) String
valueToks Either SelectiveError (WalkState, TkRecord ByteString String)
-> ((WalkState, TkRecord ByteString String)
-> Either SelectiveError WalkState)
-> Either SelectiveError WalkState
forall a b.
Either SelectiveError a
-> (a -> Either SelectiveError b) -> Either SelectiveError b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (WalkState
-> TkRecord ByteString String -> Either SelectiveError WalkState)
-> (WalkState, TkRecord ByteString String)
-> Either SelectiveError WalkState
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry WalkState
-> TkRecord ByteString String -> Either SelectiveError WalkState
go
captureVersions :: WalkState
-> Tokens b String -> Either SelectiveError (WalkState, b)
captureVersions WalkState
st Tokens b String
valueToks =
Int
-> Tokens b String
-> (TkRecord b String -> Either SelectiveError (WalkState, b))
-> Either SelectiveError (WalkState, b)
forall k a.
Int
-> Tokens k String
-> (TkRecord k String -> Either SelectiveError a)
-> Either SelectiveError a
withRecord Int
childBudget Tokens b String
valueToks ((TkRecord b String -> Either SelectiveError (WalkState, b))
-> Either SelectiveError (WalkState, b))
-> (TkRecord b String -> Either SelectiveError (WalkState, b))
-> Either SelectiveError (WalkState, b)
forall a b. (a -> b) -> a -> b
$ \TkRecord b String
versionsRec -> do
(found, count, cont) <- Int
-> Text
-> TkRecord b String
-> Either SelectiveError (Maybe Value, Int, b)
forall k.
Int
-> Text
-> TkRecord k String
-> Either SelectiveError (Maybe Value, Int, k)
findInRecord (Int
childBudget Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Text
target TkRecord b String
versionsRec
pure (st{wsSelection = (wsSelection st){svVersion = found, svVersionCount = count}, wsSeenVersions = True}, cont)
captureTime :: WalkState
-> Tokens b String -> Either SelectiveError (WalkState, b)
captureTime WalkState
st Tokens b String
valueToks =
Int
-> Tokens b String
-> (TkRecord b String -> Either SelectiveError (WalkState, b))
-> Either SelectiveError (WalkState, b)
forall k a.
Int
-> Tokens k String
-> (TkRecord k String -> Either SelectiveError a)
-> Either SelectiveError a
withRecord Int
childBudget Tokens b String
valueToks ((TkRecord b String -> Either SelectiveError (WalkState, b))
-> Either SelectiveError (WalkState, b))
-> (TkRecord b String -> Either SelectiveError (WalkState, b))
-> Either SelectiveError (WalkState, b)
forall a b. (a -> b) -> a -> b
$ \TkRecord b String
timeRec -> do
(found, _count, cont) <- Int
-> Text
-> TkRecord b String
-> Either SelectiveError (Maybe Value, Int, b)
forall k.
Int
-> Text
-> TkRecord k String
-> Either SelectiveError (Maybe Value, Int, k)
findInRecord (Int
childBudget Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Text
target TkRecord b String
timeRec
pure (st{wsSelection = (wsSelection st){svTime = found}, wsSeenTime = True}, cont)
captureName :: WalkState
-> Tokens b String -> Either SelectiveError (WalkState, b)
captureName WalkState
st Tokens b String
valueToks = do
(nameValue, cont) <- Int -> Tokens b String -> Either SelectiveError (Value, b)
forall k.
Int -> Tokens k String -> Either SelectiveError (Value, k)
materialiseWithinBudget Int
childBudget Tokens b String
valueToks
pure (st{wsSelection = (wsSelection st){svName = Just nameValue}, wsSeenName = True}, cont)