opt-env-conf 0.1.0.0 → 0.2.0.0
raw patch · 4 files changed
+154/−93 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ OptEnvConf.Lint: LintErrorManyInfinite :: LintErrorMessage
+ OptEnvConf.Lint: LintErrorNoOptionOrSwitchForDashed :: LintErrorMessage
Files
- CHANGELOG.md +8/−0
- opt-env-conf.cabal +1/−1
- src/OptEnvConf/Lint.hs +58/−10
- src/OptEnvConf/Run.hs +87/−82
CHANGELOG.md view
@@ -1,5 +1,13 @@ # Changelog +## [0.2.0.0] -- 2024-07-18++### Changed++* Fixed that the settings check could not be run with arguments.+* Added a lint to check that `long` isn't used without `option` or `switch`.+* Added a lint to check that `many` cannot be used with a parser that can succeed without consuming anything.+ ## [0.1.0.0] - 2024-07-16 ### Changed
opt-env-conf.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: opt-env-conf-version: 0.1.0.0+version: 0.2.0.0 synopsis: Settings parsing for Haskell: command-line arguments, environment variables, and configuration values. homepage: https://github.com/NorfairKing/opt-env-conf#readme bug-reports: https://github.com/NorfairKing/opt-env-conf/issues
src/OptEnvConf/Lint.hs view
@@ -46,11 +46,13 @@ | LintErrorNoDashedForOption | LintErrorNoMetavarForOption | LintErrorNoDashedForSwitch+ | LintErrorNoOptionOrSwitchForDashed | LintErrorNoReaderForEnvVar | LintErrorNoMetavarForEnvVar | LintErrorNoCommands | LintErrorUnreadableExample !String | LintErrorConfigWithoutLoad+ | LintErrorManyInfinite renderLintErrors :: NonEmpty LintError -> [Chunk] renderLintErrors =@@ -156,6 +158,17 @@ "." ] ]+ LintErrorNoOptionOrSwitchForDashed ->+ [ [ functionChunk "long",+ " or ",+ functionChunk "short",+ " has no ",+ functionChunk "option",+ " or ",+ functionChunk "switch",+ "."+ ]+ ] LintErrorNoReaderForEnvVar -> [ [ functionChunk "env", " has no ",@@ -183,6 +196,12 @@ [ [ functionChunk "conf", " was called with no way to load configuration." ]+ ]+ LintErrorManyInfinite ->+ [ [ functionChunk "many",+ " was called with a parser that may succeed without consuming anything."+ ],+ ["This is not allowed because the parser would run infinitely."] ], maybe [] (pure . ("Defined at: " :) . pure . fore cyan . chunk . T.pack . prettySrcLoc) lintErrorSrcLoc ]@@ -198,22 +217,41 @@ . runValidationT . go where- go :: Parser a -> ValidationT LintError (Reader Bool) ()+ -- Returns whether 'many' is allowed.+ -- 'many' is allowed only when every parse below consumes something.+ go :: Parser a -> ValidationT LintError (Reader Bool) Bool go = \case- ParserPure _ -> pure ()- ParserAp p1 p2 -> go p1 *> go p2- ParserSelect p1 p2 -> go p1 *> go p2- ParserEmpty _ -> pure ()- ParserAlt p1 p2 -> go p1 *> go p2- -- TODO lint if we don't try to parse anything consuming under many.- ParserMany p -> go p+ ParserPure _ -> pure False+ ParserAp p1 p2 -> do+ c1 <- go p1+ c2 <- go p2+ pure (c1 || c2)+ ParserSelect p1 p2 -> do+ c1 <- go p1+ c2 <- go p2+ pure (c1 || c2) -- TODO: is this right?+ ParserEmpty _ -> pure True+ ParserAlt p1 p2 -> do+ c1 <- go p1+ c2 <- go p2+ pure (c1 && c2) -- TODO: is this right?+ -- TODO lint if we don't try to parse anything consuming under many.+ ParserMany p -> do+ c <- go p+ when (not c) $+ mapValidationTFailure (LintError Nothing) $+ validationTFailure LintErrorManyInfinite+ pure c ParserAllOrNothing _ p -> go p ParserCheck _ _ _ p -> go p ParserCommands mLoc ls -> do if null ls then validationTFailure $ LintError mLoc LintErrorNoCommands- else traverse_ (go . commandParser) ls- ParserWithConfig p1 p2 -> go p1 *> local (const True) (go p2)+ else and <$> traverse (go . commandParser) ls -- TODO is this right?+ ParserWithConfig p1 p2 -> do+ c1 <- go p1+ c2 <- local (const True) (go p2)+ pure $ c1 || c2 ParserSetting mLoc Setting {..} -> mapValidationTFailure (LintError mLoc) $ do case settingHelp of Nothing ->@@ -246,6 +284,8 @@ validationTFailure LintErrorNoMetavarForOption when (isJust settingSwitchValue && null settingDasheds) $ validationTFailure LintErrorNoDashedForSwitch+ when (not settingTryOption && isNothing settingSwitchValue && not (null settingDasheds)) $+ validationTFailure LintErrorNoOptionOrSwitchForDashed when (isJust settingEnvVars && null settingReaders) $ validationTFailure LintErrorNoReaderForEnvVar when (isJust settingEnvVars && not settingHidden && isNothing settingMetavar) $@@ -257,3 +297,11 @@ hasConfig <- ask when (isJust settingConfigVals && not hasConfig) $ validationTFailure LintErrorConfigWithoutLoad+ pure $+ -- 'many' is only allowed if something is being consumed and it's+ -- impossible for nothing to be consumed.+ and+ [ settingTryArgument || settingTryOption || isJust settingSwitchValue,+ null settingEnvVars,+ null settingConfigVals+ ]
src/OptEnvConf/Run.hs view
@@ -188,95 +188,100 @@ internalParser :: Version -> Parser a -> Parser (Internal a) internalParser version p =- choice- [ setting- [ switch ShowHelp,- short 'h',- long "help",- help "Show this help text"- ],- setting- [ switch ShowVersion,- long "version",- help $ "Output version information: " <> showVersion version- ],- setting- [ switch RenderMan,- long "render-man-page",- hidden,- help "Show this help text"- ],- setting- [ switch CheckSettings,- long $ NE.toList settingsCheckSwitch,- hidden,- help "Run the parser and exit if parsing succeeded."- ],- BashCompletionScript- <$> mapIO- parseAbsFile- ( setting- [ option,- reader str,- long "bash-completion-script",+ let allowLeftovers :: Parser a -> Parser a+ allowLeftovers p' = fst <$> ((,) <$> p' <*> many (setting [reader str, argument, hidden] :: Parser String))+ in choice+ [ allowLeftovers $+ setting+ [ switch ShowHelp,+ short 'h',+ long "help",+ help "Show this help text"+ ],+ allowLeftovers $+ setting+ [ switch ShowVersion,+ long "version",+ help $ "Output version information: " <> showVersion version+ ],+ setting+ [ switch RenderMan,+ long "render-man-page",+ hidden,+ help "Show this help text"+ ],+ allowLeftovers $+ setting+ [ switch CheckSettings,+ long $ NE.toList settingsCheckSwitch, hidden,- help "Render the bash completion script"- ]- ),- ZshCompletionScript- <$> mapIO- parseAbsFile- ( setting- [ option,- reader str,- long "zsh-completion-script",+ help "Run the parser and exit if parsing succeeded."+ ],+ BashCompletionScript+ <$> mapIO+ parseAbsFile+ ( setting+ [ option,+ reader str,+ long "bash-completion-script",+ hidden,+ help "Render the bash completion script"+ ]+ ),+ ZshCompletionScript+ <$> mapIO+ parseAbsFile+ ( setting+ [ option,+ reader str,+ long "zsh-completion-script",+ hidden,+ help "Render the zsh completion script"+ ]+ ),+ ZshCompletionScript+ <$> mapIO+ parseAbsFile+ ( setting+ [ option,+ reader str,+ long "fish-completion-script",+ hidden,+ help "Render the fish completion script"+ ]+ ),+ setting+ [ help "Query completion",+ switch CompletionQuery,+ -- Long string that no normal user would ever use.+ long "query-opt-env-conf-completion",+ hidden+ ]+ <*> setting+ [ switch True,+ long "completion-enriched",+ value False, hidden,- help "Render the zsh completion script"+ help "Whether to enable enriched completion" ]- ),- ZshCompletionScript- <$> mapIO- parseAbsFile- ( setting+ <*> setting [ option,- reader str,- long "fish-completion-script",+ reader auto,+ long "completion-index", hidden,- help "Render the fish completion script"+ help "The index between the arguments where completion was invoked." ]- ),- setting- [ help "Query completion",- switch CompletionQuery,- -- Long string that no normal user would ever use.- long "query-opt-env-conf-completion",- hidden+ <*> many+ ( setting+ [ option,+ reader str,+ long "completion-word",+ hidden,+ help "The words (arguments) that have already been typed"+ ]+ ),+ ParsedNormally <$> p ]- <*> setting- [ switch True,- long "completion-enriched",- value False,- hidden,- help "Whether to enable enriched completion"- ]- <*> setting- [ option,- reader auto,- long "completion-index",- hidden,- help "The index between the arguments where completion was invoked."- ]- <*> many- ( setting- [ option,- reader str,- long "completion-word",- hidden,- help "The words (arguments) that have already been typed"- ]- ),- ParsedNormally <$> p- ] -- | Run a parser on given arguments and environment instead of getting them -- from the current process.