{-# LANGUAGE LambdaCase #-}

module Restyler.Restyler
    ( Restyler(..)
    , getAllRestylersVersioned

    -- * Exported for testing
    , upgradeEnabled
    )
where

import Restyler.Prelude

import Data.Aeson
import Data.Aeson.Casing
import qualified Data.HashMap.Lazy as HM
import Data.Yaml (decodeFileThrow)
import Restyler.App.Class
import Restyler.Config.ExpectedKeys
import Restyler.Config.Include
import Restyler.Config.Interpreter
import Restyler.Delimited
import Restyler.RemoteFile

data Restyler = Restyler
    { Restyler -> Bool
rEnabled :: Bool
    , Restyler -> String
rName :: String
    , Restyler -> String
rImage :: String
    , Restyler -> [String]
rCommand :: [String]
    , Restyler -> [String]
rArguments :: [String]
    , Restyler -> [Include]
rInclude :: [Include]
    , Restyler -> [Interpreter]
rInterpreters :: [Interpreter]
    , Restyler -> Maybe Delimiters
rDelimiters :: Maybe Delimiters
    , Restyler -> Bool
rSupportsArgSep :: Bool
    , Restyler -> Bool
rSupportsMultiplePaths :: Bool
    , Restyler -> [String]
rDocumentation :: [String]
    }
    deriving (Restyler -> Restyler -> Bool
(Restyler -> Restyler -> Bool)
-> (Restyler -> Restyler -> Bool) -> Eq Restyler
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Restyler -> Restyler -> Bool
$c/= :: Restyler -> Restyler -> Bool
== :: Restyler -> Restyler -> Bool
$c== :: Restyler -> Restyler -> Bool
Eq, Int -> Restyler -> ShowS
[Restyler] -> ShowS
Restyler -> String
(Int -> Restyler -> ShowS)
-> (Restyler -> String) -> ([Restyler] -> ShowS) -> Show Restyler
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Restyler] -> ShowS
$cshowList :: [Restyler] -> ShowS
show :: Restyler -> String
$cshow :: Restyler -> String
showsPrec :: Int -> Restyler -> ShowS
$cshowsPrec :: Int -> Restyler -> ShowS
Show, (forall x. Restyler -> Rep Restyler x)
-> (forall x. Rep Restyler x -> Restyler) -> Generic Restyler
forall x. Rep Restyler x -> Restyler
forall x. Restyler -> Rep Restyler x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Restyler x -> Restyler
$cfrom :: forall x. Restyler -> Rep Restyler x
Generic)

instance FromJSON Restyler where
    parseJSON :: Value -> Parser Restyler
parseJSON =
        Options -> Value -> Parser Restyler
forall a.
(Generic a, GFromJSON Zero (Rep a), Selectors (Rep a)) =>
Options -> Value -> Parser a
genericParseJSONValidated (ShowS -> Options
aesonPrefix ShowS
snakeCase) (Value -> Parser Restyler)
-> (Value -> Value) -> Value -> Parser Restyler
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Value
upgradeEnabled

-- | Upgrade values from @restylers.yaml@ that lack an @enabled@ key
--
-- Hard-code a value from the list based on the default configuration present
-- here before such a key existed.
--
upgradeEnabled :: Value -> Value
upgradeEnabled :: Value -> Value
upgradeEnabled =
    (Object -> Object) -> Value -> Value
overObject ((Object -> Object) -> Value -> Value)
-> (Object -> Object) -> Value -> Value
forall a b. (a -> b) -> a -> b
$ Text -> (Object -> Value) -> Object -> Object
forall k v.
(Eq k, Hashable k) =>
k -> (HashMap k v -> v) -> HashMap k v -> HashMap k v
override "enabled" ((Object -> Value) -> Object -> Object)
-> (Object -> Value) -> Object -> Object
forall a b. (a -> b) -> a -> b
$ Bool -> Value
Bool (Bool -> Value) -> (Object -> Bool) -> Object -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> (Value -> Bool) -> Maybe Value -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True Value -> Bool
enabled (Maybe Value -> Bool) -> (Object -> Maybe Value) -> Object -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup
        "name"
  where
    overObject :: (Object -> Object) -> Value -> Value
overObject f :: Object -> Object
f = \case
        Object o :: Object
o -> Object -> Value
Object (Object -> Value) -> Object -> Value
forall a b. (a -> b) -> a -> b
$ Object -> Object
f Object
o
        v :: Value
v -> Value
v
    override :: k -> (HashMap k v -> v) -> HashMap k v -> HashMap k v
override k :: k
k f :: HashMap k v -> v
f o :: HashMap k v
o = k -> v -> HashMap k v -> HashMap k v
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
insertIfMissing k
k (HashMap k v -> v
f HashMap k v
o) HashMap k v
o
    enabled :: Value -> Bool
enabled = (Value -> [Value] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Value]
disabledRestylers)
    disabledRestylers :: [Value]
disabledRestylers =
        ["brittany", "google-java-format", "hindent", "hlint", "jdt"]

instance ToJSON Restyler where
    toJSON :: Restyler -> Value
toJSON = Options -> Restyler -> Value
forall a.
(Generic a, GToJSON Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON (Options -> Restyler -> Value) -> Options -> Restyler -> Value
forall a b. (a -> b) -> a -> b
$ ShowS -> Options
aesonPrefix ShowS
snakeCase
    toEncoding :: Restyler -> Encoding
toEncoding = Options -> Restyler -> Encoding
forall a.
(Generic a, GToJSON Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding (Options -> Restyler -> Encoding)
-> Options -> Restyler -> Encoding
forall a b. (a -> b) -> a -> b
$ ShowS -> Options
aesonPrefix ShowS
snakeCase

getAllRestylersVersioned
    :: (HasLogFunc env, HasSystem env, HasDownloadFile env)
    => String
    -> RIO env [Restyler]
getAllRestylersVersioned :: String -> RIO env [Restyler]
getAllRestylersVersioned version :: String
version = do
    -- Should downloadRemoteFile handle "unless exists" itself?
    RIO env Bool -> RIO env () -> RIO env ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM (String -> RIO env Bool
forall env. HasSystem env => String -> RIO env Bool
doesFileExist (String -> RIO env Bool) -> String -> RIO env Bool
forall a b. (a -> b) -> a -> b
$ RemoteFile -> String
rfPath RemoteFile
restylers) (RIO env () -> RIO env ()) -> RIO env () -> RIO env ()
forall a b. (a -> b) -> a -> b
$ RemoteFile -> RIO env ()
forall env.
(HasLogFunc env, HasDownloadFile env) =>
RemoteFile -> RIO env ()
downloadRemoteFile RemoteFile
restylers
    String -> RIO env [Restyler]
forall (m :: * -> *) a. (MonadIO m, FromJSON a) => String -> m a
decodeFileThrow (String -> RIO env [Restyler]) -> String -> RIO env [Restyler]
forall a b. (a -> b) -> a -> b
$ RemoteFile -> String
rfPath RemoteFile
restylers
  where
    restylers :: RemoteFile
restylers = RemoteFile :: URL -> String -> RemoteFile
RemoteFile
        { rfUrl :: URL
rfUrl = Text -> URL
URL (Text -> URL) -> Text -> URL
forall a b. (a -> b) -> a -> b
$ String -> Text
pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ ShowS
restylersYamlUrl String
version
        , rfPath :: String
rfPath = "/tmp/restylers-" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
version String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ".yaml"
        }

restylersYamlUrl :: String -> String
restylersYamlUrl :: ShowS
restylersYamlUrl version :: String
version =
    "https://raw.githubusercontent.com/restyled-io/restylers/"
        String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
version
        String -> ShowS
forall a. Semigroup a => a -> a -> a
<> "/restylers.yaml"