{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module OpenAPI.Generate.Reference
( ReferenceMap,
ComponentReference (..),
buildReferenceMap,
getSchemaReference,
getResponseReference,
getParameterReference,
getExampleReference,
getRequestBodyReference,
getHeaderReference,
getSecuritySchemeReference,
)
where
import Control.Monad
import qualified Data.Bifunctor as BF
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import Data.Text (Text)
import GHC.Generics
import qualified OpenAPI.Generate.Types as OAT
import qualified OpenAPI.Generate.Types.Schema as OAS
data ComponentReference
= SchemaReference OAS.SchemaObject
| ResponseReference OAT.ResponseObject
| ParameterReference OAT.ParameterObject
| ExampleReference OAT.ExampleObject
| RequestBodyReference OAT.RequestBodyObject
| HeaderReference OAT.HeaderObject
| SecuritySchemeReference OAT.SecuritySchemeObject
deriving (Show, Eq, Generic)
type ReferenceMap = Map.Map Text ComponentReference
buildReferenceMap :: OAT.OpenApiSpecification -> ReferenceMap
buildReferenceMap =
Map.fromList
. ( \o ->
buildReferencesForComponentType "schemas" SchemaReference (OAT.schemas o)
<> buildReferencesForComponentType "responses" ResponseReference (OAT.responses (o :: OAT.ComponentsObject))
<> buildReferencesForComponentType "parameters" ParameterReference (OAT.parameters (o :: OAT.ComponentsObject))
<> buildReferencesForComponentType "examples" ExampleReference (OAT.examples (o :: OAT.ComponentsObject))
<> buildReferencesForComponentType "requestBodies" RequestBodyReference (OAT.requestBodies o)
<> buildReferencesForComponentType "headers" HeaderReference (OAT.headers (o :: OAT.ComponentsObject))
<> buildReferencesForComponentType "securitySchemes" SecuritySchemeReference (OAT.securitySchemes o)
)
. OAT.components
buildReferencesForComponentType ::
Text ->
(a -> ComponentReference) ->
Map.Map Text (OAT.Referencable a) ->
[(Text, ComponentReference)]
buildReferencesForComponentType componentName constructor =
fmap (BF.first (("#/components/" <> componentName <> "/") <>))
. Maybe.mapMaybe (convertReferencableToReference constructor)
. Map.toList
convertReferencableToReference ::
(a -> ComponentReference) ->
(Text, OAT.Referencable a) ->
Maybe (Text, ComponentReference)
convertReferencableToReference constructor (name', OAT.Concrete object) = Just (name', constructor object)
convertReferencableToReference _ (_, OAT.Reference _) = Nothing
getReference :: Text -> ReferenceMap -> Maybe ComponentReference
getReference = Map.lookup
createReferenceLookup :: (ComponentReference -> Maybe a) -> Text -> ReferenceMap -> Maybe a
createReferenceLookup conversionFn key = getReference key >=> conversionFn
getSchemaReference :: Text -> ReferenceMap -> Maybe OAS.SchemaObject
getSchemaReference = createReferenceLookup $ \case
SchemaReference r -> Just r
_ -> Nothing
getResponseReference :: Text -> ReferenceMap -> Maybe OAT.ResponseObject
getResponseReference = createReferenceLookup $ \case
ResponseReference r -> Just r
_ -> Nothing
getParameterReference :: Text -> ReferenceMap -> Maybe OAT.ParameterObject
getParameterReference = createReferenceLookup $ \case
ParameterReference r -> Just r
_ -> Nothing
getExampleReference :: Text -> ReferenceMap -> Maybe OAT.ExampleObject
getExampleReference = createReferenceLookup $ \case
ExampleReference r -> Just r
_ -> Nothing
getRequestBodyReference :: Text -> ReferenceMap -> Maybe OAT.RequestBodyObject
getRequestBodyReference = createReferenceLookup $ \case
RequestBodyReference r -> Just r
_ -> Nothing
getHeaderReference :: Text -> ReferenceMap -> Maybe OAT.HeaderObject
getHeaderReference = createReferenceLookup $ \case
HeaderReference r -> Just r
_ -> Nothing
getSecuritySchemeReference :: Text -> ReferenceMap -> Maybe OAT.SecuritySchemeObject
getSecuritySchemeReference = createReferenceLookup $ \case
SecuritySchemeReference r -> Just r
_ -> Nothing