    {-# OPTIONS_GHC -fno-warn-deprecations #-}
    -- | Stability: unstable
    module Test.Hspec.Core.Extension {-# WARNING "This API is experimental." #-} (
    -- * Lifecycle of a test run
    {- |
    A test run goes through four distinct phases:

    1. A tree of spec items and a default `Config` are constructed in `SpecM`.
    2. Command-line options are parsed.  This transforms the default `Config` that was constructed in phase 1.
    3. The tree of spec items is transformed in various ways, depending on specific `Config` values.
    4. Each spec item is executed and its result is reported to the user.

    An extension can directly influence phase 1, and indirectly influence phases 2-4.

    When writing extensions the following imports are recommended:

    @
    import "Test.Hspec.Core.Extension"
    import "Test.Hspec.Core.Extension.Config" qualified as Config
    import "Test.Hspec.Core.Extension.Option" qualified as Option
    import "Test.Hspec.Core.Extension.Item" qualified as Item
    import "Test.Hspec.Core.Extension.Spec" qualified as Spec
    import "Test.Hspec.Core.Extension.Tree" qualified as Tree
    @
    -}

    -- ** Phase 1: Constructing a spec tree
    {- |
    - An extension can use @Spec.`Test.Hspec.Core.Extension.Spec.mapItems`@ to transform spec items in phase 1.

        * @Item.`setAnnotation`@ can be used to add custom metadata to a spec `Item`.

    - An extension can use `modifyConfig` to modify the default config.

        * @Config.`Test.Hspec.Core.Extension.Config.setAnnotation`@ can be used to add custom metadata to the default `Config`.
    -}
      runIO
    , modifyConfig

    -- ** Phase 2: Parsing command-line options
    {- |
    An extension can use `registerOptions` during phase 1 to register custom command-line options, and as a consequence indirectly influence this phase.

    * Options can use @Config.`Test.Hspec.Core.Extension.Config.setAnnotation`@ to add custom metadata to the `Config`.
    -}
    , Option
    , registerOptions

    -- ** Phase 3: Transforming the spec tree
    {- |
    An extension can use `registerTransformation` during phase 1 to indirectly influence this phase.
    -}
    , registerTransformation

    -- ** Phase 4: Reporting results
    {- |
    An extension can register a [custom formatter](https://hspec.github.io/extending-hspec-formatter.html) in phase 1 to indirectly influence this phase.
    -}

    -- * Types
    {- |
    Operations on these types are provided by the following modules respectively:

    * "Test.Hspec.Core.Extension.Config"
    * "Test.Hspec.Core.Extension.Item"
    * "Test.Hspec.Core.Extension.Spec"
    * "Test.Hspec.Core.Extension.Tree"
    -}
    , Config
    , Item
    , SpecM
    , SpecWith
    , SpecTree
    ) where

    import           Prelude ()
    import           Test.Hspec.Core.Compat

    import qualified Data.CallStack as CallStack

    import qualified GetOpt.Declarative as Declarative
    import           Test.Hspec.Core.Spec (SpecM, SpecWith, runIO, modifyConfig)
    import qualified Test.Hspec.Core.Spec as Core
    import qualified Test.Hspec.Core.Config.Definition as Core

    import           Test.Hspec.Core.Extension.Config (Config)
    import qualified Test.Hspec.Core.Extension.Config.Type as Config
    import           Test.Hspec.Core.Extension.Option
    import           Test.Hspec.Core.Extension.Item
    import           Test.Hspec.Core.Extension.Tree

    registerOptions :: HasCallStack => [Option] -> SpecWith a
    registerOptions :: forall a. HasCallStack => [Option] -> SpecWith a
    registerOptions = (Config -> Config) -> SpecWith a
    forall a. (Config -> Config) -> SpecWith a
    Core.modifyConfig ((Config -> Config) -> SpecWith a)
    -> ([Option] -> Config -> Config) -> [Option] -> SpecWith a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [Option Config] -> Config -> Config
    Core.addExtensionOptions String
    section ([Option Config] -> Config -> Config)
    -> ([Option] -> [Option Config]) -> [Option] -> Config -> Config
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Option -> Option Config) -> [Option] -> [Option Config]
    forall a b. (a -> b) -> [a] -> [b]
    map Option -> Option Config
    liftOption
      where
        section :: String
    section = String
    "OPTIONS FOR " String -> String -> String
    forall a. Semigroup a => a -> a -> a
    <> String
    package
        package :: String
    package = String
    -> ((String, SrcLoc) -> String) -> Maybe (String, SrcLoc) -> String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe String
    "main" (SrcLoc -> String
    CallStack.srcLocPackage (SrcLoc -> String)
    -> ((String, SrcLoc) -> SrcLoc) -> (String, SrcLoc) -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String, SrcLoc) -> SrcLoc
    forall a b. (a, b) -> b
    snd) Maybe (String, SrcLoc)
    HasCallStack => Maybe (String, SrcLoc)
    CallStack.callSite

        liftOption :: Option -> Declarative.Option Core.Config
        liftOption :: Option -> Option Config
    liftOption = Option -> Option Config
    Config.unOption

    {- |
    Register a transformation that transforms the spec tree in phase 3.

    The registered transformation can use:

    - @Tree.`mapItems`@ to modify spec items
    - @Tree.`filterItems`@ to discard spec items
    - @Config.`Test.Hspec.Core.Extension.Config.getAnnotation`@ to access custom config metadata
    - @Item.`getAnnotation`@ to access custom item metadata
    -}
    registerTransformation :: (Config -> [SpecTree] -> [SpecTree]) -> SpecWith a
    registerTransformation :: forall a. (Config -> [SpecTree] -> [SpecTree]) -> SpecWith a
    registerTransformation = (Config -> Config) -> SpecWith a
    forall a. (Config -> Config) -> SpecWith a
    modifyConfig ((Config -> Config) -> SpecWith a)
    -> ((Config -> [SpecTree] -> [SpecTree]) -> Config -> Config)
    -> (Config -> [SpecTree] -> [SpecTree])
    -> SpecWith a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Config -> [SpecTree] -> [SpecTree]) -> Config -> Config
    Config.addSpecTransformation