parseConfigMonoidJSON :: Object -> WarningParser ConfigMonoid
parseConfigMonoidJSON obj = do
    configMonoidDockerOpts <- jsonSubWarnings (obj ..:? "docker" ..!= mempty)
    configMonoidConnectionCount <- obj ..:? "connection-count"
    configMonoidHideTHLoading <- obj ..:? "hide-th-loading"
    configMonoidLatestSnapshotUrl <- obj ..:? "latest-snapshot-url"
    configMonoidPackageIndices <- jsonSubWarningsMT (obj ..:? "package-indices")
    configMonoidSystemGHC <- obj ..:? "system-ghc"
    configMonoidInstallGHC <- obj ..:? "install-ghc"
    configMonoidSkipGHCCheck <- obj ..:? "skip-ghc-check"
    configMonoidSkipMsys <- obj ..:? "skip-msys"
    configMonoidRequireStackVersion <- unVersionRangeJSON <$>
                                       obj ..:? "require-stack-version"
                                           ..!= VersionRangeJSON anyVersion
    configMonoidOS <- obj ..:? "os"
    configMonoidArch <- obj ..:? "arch"
    configMonoidJobs <- obj ..:? "jobs"
    configMonoidExtraIncludeDirs <- obj ..:? "extra-include-dirs" ..!= Set.empty
    configMonoidExtraLibDirs <- obj ..:? "extra-lib-dirs" ..!= Set.empty
    configMonoidConcurrentTests <- obj ..:? "concurrent-tests"
    configMonoidLocalBinPath <- obj ..:? "local-bin-path"
    configMonoidImageOpts <- jsonSubWarnings (obj ..:? "image" ..!= mempty)
    templates <- obj ..:? "templates"
    (configMonoidScmInit,configMonoidTemplateParameters) <-
      case templates of
        Nothing -> return (Nothing,M.empty)
        Just tobj -> do
          scmInit <- tobj ..:? "scm-init"
          params <- tobj ..:? "params"
          return (scmInit,fromMaybe M.empty params)
    configMonoidCompilerCheck <- obj ..:? "compiler-check"

    mghcoptions <- obj ..:? "ghc-options"
    configMonoidGhcOptions <-
        case mghcoptions of
            Nothing -> return mempty
            Just m -> fmap Map.fromList $ mapM handleGhcOptions $ Map.toList m

    extraPath <- obj ..:? "extra-path" ..!= []
    configMonoidExtraPath <- forM extraPath $
        either (fail . show) return . parseAbsDir . T.unpack

    return ConfigMonoid {..}
  where
    handleGhcOptions :: Monad m => (Text, Text) -> m (Maybe PackageName, [Text])
    handleGhcOptions (name', vals') = do
        name <-
            if name' == "*"
                then return Nothing
                else case parsePackageNameFromString $ T.unpack name' of
                        Left e -> fail $ show e
                        Right x -> return $ Just x

        case parseArgs Escaping vals' of
            Left e -> fail e
            Right vals -> return (name, map T.pack vals)

-- | Newtype for non-orphan FromJSON instance.
parseConfigMonoidJSON :: Object -> WarningParser ConfigMonoid
parseConfigMonoidJSON obj = do
    configMonoidDockerOpts <- jsonSubWarnings (obj ..:? "docker" ..!= mempty)
    configMonoidConnectionCount <- obj ..:? "connection-count"
    configMonoidHideTHLoading <- obj ..:? "hide-th-loading"
    configMonoidLatestSnapshotUrl <- obj ..:? "latest-snapshot-url"
    configMonoidPackageIndices <- jsonSubWarningsMT (obj ..:? "package-indices")
    configMonoidSystemGHC <- obj ..:? "system-ghc"
    configMonoidInstallGHC <- obj ..:? "install-ghc"
    configMonoidSkipGHCCheck <- obj ..:? "skip-ghc-check"
    configMonoidSkipMsys <- obj ..:? "skip-msys"
    configMonoidRequireStackVersion <- unVersionRangeJSON <$>
                                       obj ..:? "require-stack-version"
                                           ..!= VersionRangeJSON anyVersion
    configMonoidOS <- obj ..:? "os"
    configMonoidArch <- obj ..:? "arch"
    configMonoidJobs <- obj ..:? "jobs"
    configMonoidExtraIncludeDirs <- obj ..:? "extra-include-dirs" ..!= Set.empty
    configMonoidExtraLibDirs <- obj ..:? "extra-lib-dirs" ..!= Set.empty
    configMonoidConcurrentTests <- obj ..:? "concurrent-tests"
    configMonoidLocalBinPath <- obj ..:? "local-bin-path"
    configMonoidImageOpts <- jsonSubWarnings (obj ..:? "image" ..!= mempty)
    templates <- obj ..:? "templates"
    (configMonoidScmInit,configMonoidTemplateParameters) <-
      case templates of
        Nothing -> return (Nothing,M.empty)
        Just tobj -> do
          scmInit <- tobj ..:? "scm-init"
          params <- tobj ..:? "params"
          return (scmInit,fromMaybe M.empty params)
    configMonoidCompilerCheck <- obj ..:? "compiler-check"

    mghcoptions <- obj ..:? "ghc-options"
    configMonoidGhcOptions <-
        case mghcoptions of
            Nothing -> return mempty
            Just m -> fmap Map.fromList $ mapM handleGhcOptions $ Map.toList m

    extraPath <- obj ..:? "extra-path" ..!= []
    configMonoidExtraPath <- forM extraPath $
        either (fail . show) return . parseAbsDir . T.unpack

    return ConfigMonoid {..}
  where
    handleGhcOptions :: Monad m => (Text, Text) -> m (Maybe PackageName, [Text])
    handleGhcOptions (name', vals') = do
        name <-
            if name' == "*"
                then return Nothing
                else case parsePackageNameFromString $ T.unpack name' of
                        Left e -> fail $ show e
                        Right x -> return $ Just x

        case parseArgs Escaping vals' of
            Left e -> fail e
            Right vals -> return (name, map T.pack vals)

-- | Newtype for non-orphan FromJSON instance.
parseConfigMonoidJSON obj = do
    configMonoidDockerOpts <- jsonSubWarnings (obj ..:? "docker" ..!= mempty)
    configMonoidConnectionCount <- obj ..:? "connection-count"
    configMonoidHideTHLoading <- obj ..:? "hide-th-loading"
    configMonoidLatestSnapshotUrl <- obj ..:? "latest-snapshot-url"
    configMonoidPackageIndices <- jsonSubWarningsMT (obj ..:? "package-indices")
    configMonoidSystemGHC <- obj ..:? "system-ghc"
    configMonoidInstallGHC <- obj ..:? "install-ghc"
    configMonoidSkipGHCCheck <- obj ..:? "skip-ghc-check"
    configMonoidSkipMsys <- obj ..:? "skip-msys"
    configMonoidRequireStackVersion <- unVersionRangeJSON <$>
                                       obj ..:? "require-stack-version"
                                           ..!= VersionRangeJSON anyVersion
    configMonoidOS <- obj ..:? "os"
    configMonoidArch <- obj ..:? "arch"
    configMonoidJobs <- obj ..:? "jobs"
    configMonoidExtraIncludeDirs <- obj ..:? "extra-include-dirs" ..!= Set.empty
    configMonoidExtraLibDirs <- obj ..:? "extra-lib-dirs" ..!= Set.empty
    configMonoidConcurrentTests <- obj ..:? "concurrent-tests"
    configMonoidLocalBinPath <- obj ..:? "local-bin-path"
    configMonoidImageOpts <- jsonSubWarnings (obj ..:? "image" ..!= mempty)
    templates <- obj ..:? "templates"
    (configMonoidScmInit,configMonoidTemplateParameters) <-
      case templates of
        Nothing -> return (Nothing,M.empty)
        Just tobj -> do
          scmInit <- tobj ..:? "scm-init"
          params <- tobj ..:? "params"
          return (scmInit,fromMaybe M.empty params)
    configMonoidCompilerCheck <- obj ..:? "compiler-check"

    mghcoptions <- obj ..:? "ghc-options"
    configMonoidGhcOptions <-
        case mghcoptions of
            Nothing -> return mempty
            Just m -> fmap Map.fromList $ mapM handleGhcOptions $ Map.toList m

    extraPath <- obj ..:? "extra-path" ..!= []
    configMonoidExtraPath <- forM extraPath $
        either (fail . show) return . parseAbsDir . T.unpack

    return ConfigMonoid {..}
  where
    handleGhcOptions :: Monad m => (Text, Text) -> m (Maybe PackageName, [Text])
    handleGhcOptions (name', vals') = do
        name <-
            if name' == "*"
                then return Nothing
                else case parsePackageNameFromString $ T.unpack name' of
                        Left e -> fail $ show e
                        Right x -> return $ Just x

        case parseArgs Escaping vals' of
            Left e -> fail e
            Right vals -> return (name, map T.pack vals)

-- | Newtype for non-orphan FromJSON instance.