{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module OptEnvConf.Lint
  ( LintError (..),
    LintErrorMessage (..),
    renderLintErrors,
    renderLintError,
    lintParser,
  )
where

import Autodocodec
import Control.Monad
import Control.Monad.Reader
import qualified Data.Aeson.Types as JSON
import Data.Either
import Data.Foldable
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Maybe
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Stack (SrcLoc, prettySrcLoc)
import OptEnvConf.Args
import OptEnvConf.Parser
import qualified OptEnvConf.Reader as OptEnvConf
import OptEnvConf.Setting
import OptEnvConf.Validation
import Text.Colour

data LintError = LintError
  { LintError -> Maybe SrcLoc
lintErrorSrcLoc :: !(Maybe SrcLoc),
    LintError -> LintErrorMessage
lintErrorMessage :: !LintErrorMessage
  }

data LintErrorMessage
  = LintErrorUndocumented
  | LintErrorEmptySetting
  | LintErrorDashInShort
  | LintErrorDashInLong !(NonEmpty Char)
  | LintErrorNoReaderForArgument
  | LintErrorNoMetavarForArgument
  | LintErrorNoReaderForOption
  | LintErrorNoDashedForOption
  | LintErrorNoMetavarForOption
  | LintErrorNoDashedForSwitch
  | LintErrorNoOptionOrSwitchForDashed
  | LintErrorNoReaderForEnvVar
  | LintErrorNoMetavarForEnvVar
  | LintErrorNoCommands
  | LintErrorUnreadableExample !String
  | LintErrorUndecodableExample !String
  | LintErrorConfigWithoutLoad
  | LintErrorManyInfinite

renderLintErrors :: NonEmpty LintError -> [Chunk]
renderLintErrors :: NonEmpty LintError -> [Chunk]
renderLintErrors =
  [[Chunk]] -> [Chunk]
unlinesChunks
    ([[Chunk]] -> [Chunk])
-> (NonEmpty LintError -> [[Chunk]])
-> NonEmpty LintError
-> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Colour -> Chunk -> Chunk
fore Colour
red Chunk
"Setting parser is invalid:"] [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
:)
    ([[Chunk]] -> [[Chunk]])
-> (NonEmpty LintError -> [[Chunk]])
-> NonEmpty LintError
-> [[Chunk]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map (Chunk
"  " Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:)
    ([[Chunk]] -> [[Chunk]])
-> (NonEmpty LintError -> [[Chunk]])
-> NonEmpty LintError
-> [[Chunk]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (LintError -> [[Chunk]]) -> NonEmpty LintError -> [[Chunk]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (([] [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
:) ([[Chunk]] -> [[Chunk]])
-> (LintError -> [[Chunk]]) -> LintError -> [[Chunk]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LintError -> [[Chunk]]
renderLintError)

renderLintError :: LintError -> [[Chunk]]
renderLintError :: LintError -> [[Chunk]]
renderLintError LintError {Maybe SrcLoc
LintErrorMessage
lintErrorSrcLoc :: LintError -> Maybe SrcLoc
lintErrorMessage :: LintError -> LintErrorMessage
lintErrorSrcLoc :: Maybe SrcLoc
lintErrorMessage :: LintErrorMessage
..} =
  [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
    [ [[Colour -> Chunk -> Chunk
fore Colour
red Chunk
"Invalid Setting:"]],
      case LintErrorMessage
lintErrorMessage of
        LintErrorMessage
LintErrorUndocumented ->
          [[Chunk
"missing ", Text -> Chunk
functionChunk Text
"help", Chunk
"."]]
        LintErrorMessage
LintErrorEmptySetting ->
          [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
            [ [ [ Chunk
"This ",
                  Text -> Chunk
functionChunk Text
"setting",
                  Chunk
" parses nothing."
                ]
              ],
              [ [ Chunk
"Add an ",
                  Text -> Chunk
functionChunk Text
"argument",
                  Chunk
", ",
                  Text -> Chunk
functionChunk Text
"switch",
                  Chunk
", ",
                  Text -> Chunk
functionChunk Text
"option",
                  Chunk
", ",
                  Text -> Chunk
functionChunk Text
"env",
                  Chunk
", ",
                  Text -> Chunk
functionChunk Text
"conf",
                  Chunk
", or ",
                  Text -> Chunk
functionChunk Text
"value",
                  Chunk
"."
                ]
              ]
            ]
        LintErrorMessage
LintErrorDashInShort ->
          [ [Text -> Chunk
functionChunk Text
"short", Chunk
" may not contain a '-'."],
            [Chunk
"Found ", Text -> Chunk
functionChunk Text
"short", Chunk
" '-'."]
          ]
        LintErrorDashInLong NonEmpty Char
s ->
          [ [Text -> Chunk
functionChunk Text
"long", Chunk
" may not start with a '-'."],
            [Chunk
"Found ", Text -> Chunk
functionChunk Text
"long", Chunk
" ", Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ [Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
forall a. Show a => a -> [Char]
show ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ NonEmpty Char -> [Char]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty Char
s, Chunk
"."],
            [ Chunk
"Try ",
              Text -> Chunk
functionChunk Text
"long",
              Chunk
" ",
              Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$
                [Char] -> Text
T.pack ([Char] -> Text) -> [Char] -> Text
forall a b. (a -> b) -> a -> b
$
                  [Char] -> [Char]
forall a. Show a => a -> [Char]
show ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$
                    let go :: [Char] -> [Char]
go = \case
                          [] -> []
                          Char
'-' : [Char]
cs -> [Char] -> [Char]
go [Char]
cs
                          Char
c : [Char]
cs -> Char
c Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: [Char]
cs
                     in [Char] -> [Char]
go ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ NonEmpty Char -> [Char]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty Char
s,
              Chunk
" instead."
            ]
          ]
        LintErrorMessage
LintErrorNoReaderForArgument ->
          [ [ Text -> Chunk
functionChunk Text
"argument",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"reader",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoMetavarForArgument ->
          [ [ Text -> Chunk
functionChunk Text
"argument",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"metavar",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoReaderForOption ->
          [ [ Text -> Chunk
functionChunk Text
"option",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"reader",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoDashedForOption ->
          [ [ Text -> Chunk
functionChunk Text
"option",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"long",
              Chunk
" or ",
              Text -> Chunk
functionChunk Text
"short",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoMetavarForOption ->
          [ [ Text -> Chunk
functionChunk Text
"option",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"metavar",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoDashedForSwitch ->
          [ [ Text -> Chunk
functionChunk Text
"switch",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"long",
              Chunk
" or ",
              Text -> Chunk
functionChunk Text
"short",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoOptionOrSwitchForDashed ->
          [ [ Text -> Chunk
functionChunk Text
"long",
              Chunk
" or ",
              Text -> Chunk
functionChunk Text
"short",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"option",
              Chunk
" or ",
              Text -> Chunk
functionChunk Text
"switch",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoReaderForEnvVar ->
          [ [ Text -> Chunk
functionChunk Text
"env",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"reader",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoMetavarForEnvVar ->
          [ [ Text -> Chunk
functionChunk Text
"env",
              Chunk
" has no ",
              Text -> Chunk
functionChunk Text
"metavar",
              Chunk
"."
            ]
          ]
        LintErrorMessage
LintErrorNoCommands ->
          [ [ Text -> Chunk
functionChunk Text
"commands",
              Chunk
" was called with an empty list."
            ]
          ]
        LintErrorUnreadableExample [Char]
e ->
          [ [Text -> Chunk
functionChunk Text
"example", Chunk
" was called with an example that none of the ", Text -> Chunk
functionChunk Text
"reader", Chunk
"s succeed in reading."],
            [Chunk
"Example: ", Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ [Char] -> Text
T.pack [Char]
e]
          ]
        LintErrorUndecodableExample [Char]
e ->
          [ [Text -> Chunk
functionChunk Text
"example", Chunk
" was called with an example that none of the ", Text -> Chunk
functionChunk Text
"conf", Chunk
"s succeed in decoding."],
            [Chunk
"Example: ", Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ [Char] -> Text
T.pack [Char]
e]
          ]
        LintErrorMessage
LintErrorConfigWithoutLoad ->
          [ [ Text -> Chunk
functionChunk Text
"conf",
              Chunk
" was called with no way to load configuration."
            ]
          ]
        LintErrorMessage
LintErrorManyInfinite ->
          [ [ Text -> Chunk
functionChunk Text
"many",
              Chunk
" or ",
              Text -> Chunk
functionChunk Text
"some",
              Chunk
" was called with a parser that may succeed without consuming anything."
            ],
            [Chunk
"This is not allowed because the parser would run infinitely."]
          ],
      [[Chunk]] -> (SrcLoc -> [[Chunk]]) -> Maybe SrcLoc -> [[Chunk]]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ([Chunk] -> [[Chunk]]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Chunk] -> [[Chunk]])
-> (SrcLoc -> [Chunk]) -> SrcLoc -> [[Chunk]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Chunk
"Defined at: " Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:) ([Chunk] -> [Chunk]) -> (SrcLoc -> [Chunk]) -> SrcLoc -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Chunk -> [Chunk]
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Chunk -> [Chunk]) -> (SrcLoc -> Chunk) -> SrcLoc -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Colour -> Chunk -> Chunk
fore Colour
cyan (Chunk -> Chunk) -> (SrcLoc -> Chunk) -> SrcLoc -> Chunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Chunk
chunk (Text -> Chunk) -> (SrcLoc -> Text) -> SrcLoc -> Chunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack ([Char] -> Text) -> (SrcLoc -> [Char]) -> SrcLoc -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SrcLoc -> [Char]
prettySrcLoc) Maybe SrcLoc
lintErrorSrcLoc
    ]

functionChunk :: Text -> Chunk
functionChunk :: Text -> Chunk
functionChunk = Colour -> Chunk -> Chunk
fore Colour
yellow (Chunk -> Chunk) -> (Text -> Chunk) -> Text -> Chunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Chunk
chunk

lintParser :: Parser a -> Maybe (NonEmpty LintError)
lintParser :: forall a. Parser a -> Maybe (NonEmpty LintError)
lintParser =
  (NonEmpty LintError -> Maybe (NonEmpty LintError))
-> (Bool -> Maybe (NonEmpty LintError))
-> Either (NonEmpty LintError) Bool
-> Maybe (NonEmpty LintError)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either NonEmpty LintError -> Maybe (NonEmpty LintError)
forall a. a -> Maybe a
Just (Maybe (NonEmpty LintError) -> Bool -> Maybe (NonEmpty LintError)
forall a b. a -> b -> a
const Maybe (NonEmpty LintError)
forall a. Maybe a
Nothing)
    (Either (NonEmpty LintError) Bool -> Maybe (NonEmpty LintError))
-> (Parser a -> Either (NonEmpty LintError) Bool)
-> Parser a
-> Maybe (NonEmpty LintError)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Validation LintError Bool -> Either (NonEmpty LintError) Bool
forall e a. Validation e a -> Either (NonEmpty e) a
validationToEither
    (Validation LintError Bool -> Either (NonEmpty LintError) Bool)
-> (Parser a -> Validation LintError Bool)
-> Parser a
-> Either (NonEmpty LintError) Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Reader Bool (Validation LintError Bool)
-> Bool -> Validation LintError Bool
forall r a. Reader r a -> r -> a
`runReader` Bool
False) -- Set to true for parsers that have a way to load conf
    (Reader Bool (Validation LintError Bool)
 -> Validation LintError Bool)
-> (Parser a -> Reader Bool (Validation LintError Bool))
-> Parser a
-> Validation LintError Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ValidationT LintError (ReaderT Bool Identity) Bool
-> Reader Bool (Validation LintError Bool)
forall e (m :: * -> *) a. ValidationT e m a -> m (Validation e a)
runValidationT
    (ValidationT LintError (ReaderT Bool Identity) Bool
 -> Reader Bool (Validation LintError Bool))
-> (Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool)
-> Parser a
-> Reader Bool (Validation LintError Bool)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go
  where
    -- Returns whether 'many' is allowed.
    -- 'many' is allowed only when every parse below consumes something.
    go :: Parser a -> ValidationT LintError (Reader Bool) Bool
    go :: forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go = \case
      ParserPure a
_ -> Bool -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a. a -> ValidationT LintError (ReaderT Bool Identity) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
      ParserAp Parser (a1 -> a)
p1 Parser a1
p2 -> do
        Bool
c1 <- Parser (a1 -> a)
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser (a1 -> a)
p1
        Bool
c2 <- Parser a1 -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a1
p2
        pure (Bool
c1 Bool -> Bool -> Bool
|| Bool
c2)
      ParserSelect Parser (Either a1 a)
p1 Parser (a1 -> a)
p2 -> do
        Bool
c1 <- Parser (Either a1 a)
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser (Either a1 a)
p1
        Bool
c2 <- Parser (a1 -> a)
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser (a1 -> a)
p2
        pure (Bool
c1 Bool -> Bool -> Bool
|| Bool
c2) -- TODO: is this right?
      ParserEmpty Maybe SrcLoc
_ -> Bool -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a. a -> ValidationT LintError (ReaderT Bool Identity) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
      ParserAlt Parser a
p1 Parser a
p2 -> do
        Bool
c1 <- Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a
p1
        Bool
c2 <- Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a
p2
        pure (Bool
c1 Bool -> Bool -> Bool
&& Bool
c2) -- TODO: is this right?
        -- TODO lint if we don't try to parse anything consuming under many.
      ParserMany Parser a1
p -> do
        Bool
c <- Parser a1 -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a1
p
        Bool
-> ValidationT LintError (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
c) (ValidationT LintError (ReaderT Bool Identity) ()
 -> ValidationT LintError (ReaderT Bool Identity) ())
-> ValidationT LintError (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          (LintErrorMessage -> LintError)
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall (m :: * -> *) e1 e2 a.
Functor m =>
(e1 -> e2) -> ValidationT e1 m a -> ValidationT e2 m a
mapValidationTFailure (Maybe SrcLoc -> LintErrorMessage -> LintError
LintError Maybe SrcLoc
forall a. Maybe a
Nothing) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintError (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
            LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorManyInfinite
        pure Bool
c
      ParserSome Parser a1
p -> do
        Bool
c <- Parser a1 -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a1
p
        Bool
-> ValidationT LintError (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
c) (ValidationT LintError (ReaderT Bool Identity) ()
 -> ValidationT LintError (ReaderT Bool Identity) ())
-> ValidationT LintError (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          (LintErrorMessage -> LintError)
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall (m :: * -> *) e1 e2 a.
Functor m =>
(e1 -> e2) -> ValidationT e1 m a -> ValidationT e2 m a
mapValidationTFailure (Maybe SrcLoc -> LintErrorMessage -> LintError
LintError Maybe SrcLoc
forall a. Maybe a
Nothing) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintError (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintError (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
            LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorManyInfinite
        pure Bool
c
      ParserAllOrNothing Maybe SrcLoc
_ Parser a
p -> Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a
p
      ParserCheck Maybe SrcLoc
_ Bool
_ a1 -> IO (Either [Char] a)
_ Parser a1
p -> Parser a1 -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a1
p
      ParserCommands Maybe SrcLoc
mLoc [Command a]
ls -> do
        if [Command a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Command a]
ls
          then LintError -> ValidationT LintError (ReaderT Bool Identity) Bool
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure (LintError -> ValidationT LintError (ReaderT Bool Identity) Bool)
-> LintError -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a b. (a -> b) -> a -> b
$ Maybe SrcLoc -> LintErrorMessage -> LintError
LintError Maybe SrcLoc
mLoc LintErrorMessage
LintErrorNoCommands
          else [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool)
-> ValidationT LintError (ReaderT Bool Identity) [Bool]
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Command a -> ValidationT LintError (ReaderT Bool Identity) Bool)
-> [Command a]
-> ValidationT LintError (ReaderT Bool Identity) [Bool]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse (Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go (Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool)
-> (Command a -> Parser a)
-> Command a
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Command a -> Parser a
forall a. Command a -> Parser a
commandParser) [Command a]
ls -- TODO is this right?
      ParserWithConfig Maybe SrcLoc
_ Parser (Maybe Object)
p1 Parser a
p2 -> do
        Bool
c1 <- Parser (Maybe Object)
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser (Maybe Object)
p1
        Bool
c2 <- (Bool -> Bool)
-> ValidationT LintError (ReaderT Bool Identity) Bool
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
(Bool -> Bool)
-> ValidationT LintError (ReaderT Bool Identity) a
-> ValidationT LintError (ReaderT Bool Identity) a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (Bool -> Bool -> Bool
forall a b. a -> b -> a
const Bool
True) (Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
forall a.
Parser a -> ValidationT LintError (ReaderT Bool Identity) Bool
go Parser a
p2)
        pure $ Bool
c1 Bool -> Bool -> Bool
|| Bool
c2
      ParserSetting Maybe SrcLoc
mLoc Setting {Bool
[[Char]]
[Dashed]
[Reader a]
Maybe a
Maybe [Char]
Maybe (NonEmpty [Char])
Maybe (NonEmpty (ConfigValSetting a))
Maybe (a, [Char])
settingDasheds :: [Dashed]
settingReaders :: [Reader a]
settingTryArgument :: Bool
settingSwitchValue :: Maybe a
settingTryOption :: Bool
settingEnvVars :: Maybe (NonEmpty [Char])
settingConfigVals :: Maybe (NonEmpty (ConfigValSetting a))
settingDefaultValue :: Maybe (a, [Char])
settingExamples :: [[Char]]
settingHidden :: Bool
settingMetavar :: Maybe [Char]
settingHelp :: Maybe [Char]
settingDasheds :: forall a. Setting a -> [Dashed]
settingReaders :: forall a. Setting a -> [Reader a]
settingTryArgument :: forall a. Setting a -> Bool
settingSwitchValue :: forall a. Setting a -> Maybe a
settingTryOption :: forall a. Setting a -> Bool
settingEnvVars :: forall a. Setting a -> Maybe (NonEmpty [Char])
settingConfigVals :: forall a. Setting a -> Maybe (NonEmpty (ConfigValSetting a))
settingDefaultValue :: forall a. Setting a -> Maybe (a, [Char])
settingExamples :: forall a. Setting a -> [[Char]]
settingHidden :: forall a. Setting a -> Bool
settingMetavar :: forall a. Setting a -> Maybe [Char]
settingHelp :: forall a. Setting a -> Maybe [Char]
..} -> (LintErrorMessage -> LintError)
-> ValidationT LintErrorMessage (ReaderT Bool Identity) Bool
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall (m :: * -> *) e1 e2 a.
Functor m =>
(e1 -> e2) -> ValidationT e1 m a -> ValidationT e2 m a
mapValidationTFailure (Maybe SrcLoc -> LintErrorMessage -> LintError
LintError Maybe SrcLoc
mLoc) (ValidationT LintErrorMessage (ReaderT Bool Identity) Bool
 -> ValidationT LintError (ReaderT Bool Identity) Bool)
-> ValidationT LintErrorMessage (ReaderT Bool Identity) Bool
-> ValidationT LintError (ReaderT Bool Identity) Bool
forall a b. (a -> b) -> a -> b
$ do
        case Maybe [Char]
settingHelp of
          Maybe [Char]
Nothing ->
            -- Hidden values may be undocumented
            Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
settingHidden) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$ LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorUndocumented
          Just [Char]
_ -> () -> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a.
a -> ValidationT LintErrorMessage (ReaderT Bool Identity) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when
          ( [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and
              [ Bool -> Bool
not Bool
settingTryArgument,
                Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
settingSwitchValue,
                Bool -> Bool
not Bool
settingTryOption,
                Maybe (NonEmpty [Char]) -> Bool
forall a. Maybe a -> Bool
isNothing Maybe (NonEmpty [Char])
settingEnvVars,
                Maybe (NonEmpty (ConfigValSetting a)) -> Bool
forall a. Maybe a -> Bool
isNothing Maybe (NonEmpty (ConfigValSetting a))
settingConfigVals
              ]
          )
          (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$ LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorEmptySetting
        [Dashed]
-> (Dashed
    -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Dashed]
settingDasheds ((Dashed
  -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> (Dashed
    -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$ \case
          DashedLong cs :: NonEmpty Char
cs@(Char
'-' :| [Char]
_) -> LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure (LintErrorMessage
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$ NonEmpty Char -> LintErrorMessage
LintErrorDashInLong NonEmpty Char
cs
          DashedShort Char
'-' -> LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorDashInShort
          Dashed
_ -> () -> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a.
a -> ValidationT LintErrorMessage (ReaderT Bool Identity) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
settingTryArgument Bool -> Bool -> Bool
&& [Reader a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Reader a]
settingReaders) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoReaderForArgument
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
settingTryArgument Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
settingHidden Bool -> Bool -> Bool
&& Maybe [Char] -> Bool
forall a. Maybe a -> Bool
isNothing Maybe [Char]
settingMetavar) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoMetavarForArgument
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
settingTryOption Bool -> Bool -> Bool
&& [Reader a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Reader a]
settingReaders) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoReaderForOption
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
settingTryOption Bool -> Bool -> Bool
&& [Dashed] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Dashed]
settingDasheds) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoDashedForOption
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
settingTryOption Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
settingHidden Bool -> Bool -> Bool
&& Maybe [Char] -> Bool
forall a. Maybe a -> Bool
isNothing Maybe [Char]
settingMetavar) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoMetavarForOption
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
settingSwitchValue Bool -> Bool -> Bool
&& [Dashed] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Dashed]
settingDasheds) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoDashedForSwitch
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
settingTryOption Bool -> Bool -> Bool
&& Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
settingSwitchValue Bool -> Bool -> Bool
&& Bool -> Bool
not ([Dashed] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Dashed]
settingDasheds)) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoOptionOrSwitchForDashed
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe (NonEmpty [Char]) -> Bool
forall a. Maybe a -> Bool
isJust Maybe (NonEmpty [Char])
settingEnvVars Bool -> Bool -> Bool
&& [Reader a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Reader a]
settingReaders) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoReaderForEnvVar
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe (NonEmpty [Char]) -> Bool
forall a. Maybe a -> Bool
isJust Maybe (NonEmpty [Char])
settingEnvVars Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
settingHidden Bool -> Bool -> Bool
&& Maybe [Char] -> Bool
forall a. Maybe a -> Bool
isNothing Maybe [Char]
settingMetavar) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorNoMetavarForEnvVar
        [[Char]]
-> ([Char]
    -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [[Char]]
settingExamples (([Char]
  -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ([Char]
    -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$ \[Char]
e ->
          let canRead :: Reader a -> Bool
canRead Reader a
r = Either [Char] a -> Bool
forall a b. Either a b -> Bool
isRight (Either [Char] a -> Bool) -> Either [Char] a -> Bool
forall a b. (a -> b) -> a -> b
$ Reader a -> [Char] -> Either [Char] a
forall a. Reader a -> [Char] -> Either [Char] a
OptEnvConf.runReader Reader a
r [Char]
e
           in Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ((Bool
settingTryArgument Bool -> Bool -> Bool
|| Bool
settingTryOption) Bool -> Bool -> Bool
&& Bool -> Bool
not ((Reader a -> Bool) -> [Reader a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Reader a -> Bool
canRead [Reader a]
settingReaders)) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
                LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure (LintErrorMessage
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
                  [Char] -> LintErrorMessage
LintErrorUnreadableExample [Char]
e
        [[Char]]
-> ([Char]
    -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [[Char]]
settingExamples (([Char]
  -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ([Char]
    -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$ \[Char]
e ->
          let canDecode :: ConfigValSetting a -> Bool
canDecode (ConfigValSetting NonEmpty [Char]
_ ValueCodec void (Maybe a)
c) = Either [Char] (Maybe a) -> Bool
forall a b. Either a b -> Bool
isRight (Either [Char] (Maybe a) -> Bool)
-> Either [Char] (Maybe a) -> Bool
forall a b. (a -> b) -> a -> b
$ (Value -> Parser (Maybe a)) -> Value -> Either [Char] (Maybe a)
forall a b. (a -> Parser b) -> a -> Either [Char] b
JSON.parseEither (ValueCodec void (Maybe a) -> Value -> Parser (Maybe a)
forall void a. ValueCodec void a -> Value -> Parser a
parseJSONVia ValueCodec void (Maybe a)
c) (Text -> Value
JSON.String ([Char] -> Text
T.pack [Char]
e))
           in Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe (NonEmpty (ConfigValSetting a)) -> Bool
forall a. Maybe a -> Bool
isJust Maybe (NonEmpty (ConfigValSetting a))
settingConfigVals Bool -> Bool -> Bool
&& Bool -> Bool
not ((ConfigValSetting a -> Bool) -> [ConfigValSetting a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ConfigValSetting a -> Bool
canDecode ([ConfigValSetting a]
-> (NonEmpty (ConfigValSetting a) -> [ConfigValSetting a])
-> Maybe (NonEmpty (ConfigValSetting a))
-> [ConfigValSetting a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] NonEmpty (ConfigValSetting a) -> [ConfigValSetting a]
forall a. NonEmpty a -> [a]
NE.toList Maybe (NonEmpty (ConfigValSetting a))
settingConfigVals))) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
                LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure (LintErrorMessage
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
                  [Char] -> LintErrorMessage
LintErrorUndecodableExample [Char]
e
        Bool
hasConfig <- ValidationT LintErrorMessage (ReaderT Bool Identity) Bool
forall r (m :: * -> *). MonadReader r m => m r
ask
        Bool
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe (NonEmpty (ConfigValSetting a)) -> Bool
forall a. Maybe a -> Bool
isJust Maybe (NonEmpty (ConfigValSetting a))
settingConfigVals Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
hasConfig) (ValidationT LintErrorMessage (ReaderT Bool Identity) ()
 -> ValidationT LintErrorMessage (ReaderT Bool Identity) ())
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall a b. (a -> b) -> a -> b
$
          LintErrorMessage
-> ValidationT LintErrorMessage (ReaderT Bool Identity) ()
forall (m :: * -> *) e a. Applicative m => e -> ValidationT e m a
validationTFailure LintErrorMessage
LintErrorConfigWithoutLoad
        pure $
          -- 'many' is only allowed if something is being consumed and it's
          -- impossible for nothing to be consumed.
          [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and
            [ Bool
settingTryArgument Bool -> Bool -> Bool
|| Bool
settingTryOption Bool -> Bool -> Bool
|| Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
settingSwitchValue,
              Maybe (NonEmpty [Char]) -> Bool
forall a. Maybe a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Maybe (NonEmpty [Char])
settingEnvVars,
              Maybe (NonEmpty (ConfigValSetting a)) -> Bool
forall a. Maybe a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Maybe (NonEmpty (ConfigValSetting a))
settingConfigVals
            ]