packages feed

jordan-openapi 0.1.0.0 → 0.2.0.0

raw patch · 6 files changed

+285/−165 lines, 6 filesdep +http-typesdep ~aesondep ~basedep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: http-types

Dependency ranges changed: aeson, base, bytestring, insert-ordered-containers, jordan, openapi3

API changes (from Hackage documentation)

+ Jordan.OpenAPI: JordanToJSONSchema :: a -> JordanToJSONSchema a
+ Jordan.OpenAPI: [getJordanToJSONSchema] :: JordanToJSONSchema a -> a
+ Jordan.OpenAPI: getFromRef :: forall a. FromJSON a => Proxy a -> Declare (Definitions Schema) (Referenced Schema)
+ Jordan.OpenAPI: getToRef :: forall a. ToJSON a => Proxy a -> Declare (Definitions Schema) (Referenced Schema)
+ Jordan.OpenAPI: newtype JordanToJSONSchema a
+ Jordan.OpenAPI.Internal: PropertyDeclare :: [Text] -> InsOrdHashMap Text (Referenced Schema) -> PropertyDeclare
+ Jordan.OpenAPI.Internal: [propertyTypes] :: PropertyDeclare -> InsOrdHashMap Text (Referenced Schema)
+ Jordan.OpenAPI.Internal: [requiredProperties] :: PropertyDeclare -> [Text]
+ Jordan.OpenAPI.Internal: addDescription :: Text -> Referenced Schema -> Referenced Schema
+ Jordan.OpenAPI.Internal: bothHaveEnum :: Schema -> Schema -> Bool
+ Jordan.OpenAPI.Internal: combineInline :: Schema -> Schema -> Schema
+ Jordan.OpenAPI.Internal: data PropertyDeclare
+ Jordan.OpenAPI.Internal: encodeRefName :: Text -> Text
+ Jordan.OpenAPI.Internal: enumValues :: Schema -> [Value]
+ Jordan.OpenAPI.Internal: getFromRef :: forall a. FromJSON a => Proxy a -> Declare (Definitions Schema) (Referenced Schema)
+ Jordan.OpenAPI.Internal: getToRef :: forall a. ToJSON a => Proxy a -> Declare (Definitions Schema) (Referenced Schema)
+ Jordan.OpenAPI.Internal: instance GHC.Base.Monoid Jordan.OpenAPI.Internal.PropertyDeclare
+ Jordan.OpenAPI.Internal: instance GHC.Base.Semigroup Jordan.OpenAPI.Internal.PropertyDeclare
+ Jordan.OpenAPI.Internal: instance GHC.Generics.Generic Jordan.OpenAPI.Internal.PropertyDeclare
+ Jordan.OpenAPI.Internal: instance GHC.Show.Show Jordan.OpenAPI.Internal.PropertyDeclare
+ Jordan.OpenAPI.Internal: sameTypes :: Schema -> Schema -> Bool
- Jordan.OpenAPI.Internal: ObjectSchema :: Declare (Definitions Schema) Schema -> ObjectSchema a
+ Jordan.OpenAPI.Internal: ObjectSchema :: Declare (Definitions Schema) PropertyDeclare -> ObjectSchema a
- Jordan.OpenAPI.Internal: [getObjectSchema] :: ObjectSchema a -> Declare (Definitions Schema) Schema
+ Jordan.OpenAPI.Internal: [getObjectSchema] :: ObjectSchema a -> Declare (Definitions Schema) PropertyDeclare

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for jordan-openapi +## 0.2.0.0 -- 2022-07-04++* Updated library to be compatible with `jordan` version `0.2.0.0`+* Added *lots* of documenation.+ ## 0.1.0.0 -- YYYY-mm-dd  * First version. Released on an unsuspecting world.
jordan-openapi.cabal view
@@ -1,10 +1,11 @@ cabal-version:      3.0 name:               jordan-openapi-version:            0.1.0.0+version:            0.2.0.0 synopsis:           OpenAPI Definitions for Jordan, Automatically  -- A longer description of the package.--- description:+description:+  Automatic generation of documentation for Jordan-powered types. homepage:  -- A URL where users can report bugs.@@ -21,15 +22,18 @@  common build-deps   build-depends:-      aeson  >= 1.5.6 && <1.6-    , bytestring >= 0.10.12 && <0.11+      aeson  >= 1.5.6 && <2.3+    , bytestring >= 0.10.12 && <0.12     , containers >= 0.6.2 && <0.7     , contravariant >= 1.5.5 && <1.6     , insert-ordered-containers >= 0.2.5 && <0.3-    , jordan >= 0.1.0.0 && <0.2-    , openapi3 >= 3.1.0 && <3.2+    , jordan >= 0.2.0.0 && <0.3+    , openapi3 >= 3.1.0 && <3.3     , optics-core >= 0.4 && <0.5     , text >= 1.2.4 && <1.3+    , insert-ordered-containers >=0.2.3 && <0.3+    , http-types >= 0.12.2 && <0.13+    , base >= 4.14.1 && <4.17  library     import: build-deps@@ -42,7 +46,6 @@      -- LANGUAGE extensions used by modules in this package.     -- other-extensions:-    build-depends:    base ^>=4.14.1.0     hs-source-dirs:   lib     default-language: Haskell2010 @@ -52,9 +55,8 @@     default-language: Haskell2010     type:             exitcode-stdio-1.0     hs-source-dirs:   test-    main-is:          JordanOpenApiSpec.hs +    main-is:          JordanOpenApiSpec.hs     other-modules:         Jordan.OpenAPI.SpecDefs     build-depends:-        base ^>=4.14.1.0-      , hspec+        hspec
lib/Jordan/OpenAPI.hs view
@@ -1,25 +1,33 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ScopedTypeVariables #-}+ module Jordan.OpenAPI-    ( getFromNamed-    , getToNamed-    , JordanFromJSONSchema (..)-    ) where+  ( -- * Documenting FromJSON Schemas+    getFromNamed,+    getToNamed, +    -- * Documenting ToJSON schemas+    getFromRef,+    getToRef,++    -- * Newtype wrappers for DerivingVia+    JordanFromJSONSchema (..),+    JordanToJSONSchema (..),+  )+where+ import Data.Functor.Contravariant (contramap)-import Data.OpenApi.Schema (ToSchema(..))-import Data.Proxy (Proxy(..))-import Data.Typeable (Typeable(..))-import Jordan.FromJSON.Class (FromJSON(..))-import Jordan.OpenAPI.Internal (getFromNamed, getToNamed)-import Jordan.ToJSON.Class (ToJSON(..))+import Data.OpenApi.Schema (ToSchema (..))+import Data.Proxy (Proxy (..))+import Data.Typeable (Typeable (..))+import Jordan.FromJSON.Class (FromJSON (..))+import Jordan.OpenAPI.Internal (getFromNamed, getFromRef, getToNamed, getToRef)+import Jordan.ToJSON.Class (ToJSON (..))  -- | Newtype for use with DerivingVia. -- -- Allows deriving 'Data.OpenApi.Schema.ToSchema' via DerivingVia, using the Jordan -- defintion of 'Jordan.ToJSON.Class.ToJSON'.-newtype JordanFromJSONSchema a-  = JordanFromJSONSchema { getJordanFromJSONSchema :: a }+newtype JordanFromJSONSchema a = JordanFromJSONSchema {getJordanFromJSONSchema :: a}  instance (FromJSON a) => FromJSON (JordanFromJSONSchema a) where   fromJSON = JordanFromJSONSchema <$> fromJSON@@ -31,8 +39,7 @@ -- -- Allows deriving 'Data.OpenApi.Schema.ToSchema' via DerivingVia, using the Jordan -- defintion of 'Jordan.ToJSON.Class.ToJSON'.-newtype JordanToJSONSchema a-  = JordanToJSONSchema { getJordanToJSONSchema :: a }+newtype JordanToJSONSchema a = JordanToJSONSchema {getJordanToJSONSchema :: a}  instance (ToJSON a) => ToJSON (JordanToJSONSchema a) where   toJSON = contramap getJordanToJSONSchema toJSON
lib/Jordan/OpenAPI/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE InstanceSigs #-}@@ -5,37 +6,47 @@ {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-module Jordan.OpenAPI.Internal-    where -import Control.Applicative (Alternative(..))-import Control.Monad (unless)+-- | Internal module that provides JSON parser and serializers that convert to OpenAPI documentation.+--+-- Note that this module is full of internal-use-only functions and should probably n ever actually be imported.+module Jordan.OpenAPI.Internal where++import Control.Applicative (Alternative (..))+import Control.Monad (unless, when) import qualified Data.Aeson.Types as Aeson+import Data.Function (on) import Data.Functor (void)-import Data.Functor.Const-import Data.Functor.Contravariant-import Data.Functor.Contravariant.Divisible+import Data.Functor.Contravariant (Contravariant (contramap))+import Data.Functor.Contravariant.Divisible (Divisible (..)) import qualified Data.HashMap.Strict.InsOrd as InsOrd import Data.Maybe (fromMaybe) import Data.OpenApi.Declare import Data.OpenApi.Internal import Data.OpenApi.Internal.Schema (rename, unname, unnamed) import Data.OpenApi.Optics-import Data.Proxy (Proxy(..))+import Data.Proxy (Proxy (..)) import qualified Data.Text as T+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import Debug.Trace (trace, traceM, traceShowId)+import GHC.Generics+import GHC.Stack (HasCallStack) import Jordan.FromJSON.Class import Jordan.ToJSON.Class+import Network.HTTP.Types.URI (urlEncode) import Optics.At.Core+import Optics.Iso (non) import Optics.Operators-import Optics.Optic ((%))+import Optics.Optic ((%), (&)) -newtype ConstDeclare env r a-  = ConstDeclare { runConstDeclare :: Declare env r }+-- | Declare with a phantom type parameter.+newtype ConstDeclare env r a = ConstDeclare {runConstDeclare :: Declare env r} +-- | Fmap ignores argument instance Functor (ConstDeclare env r) where   fmap _ (ConstDeclare d) = ConstDeclare d +-- | Applicative combines declarations. instance (Monoid r, Monoid env) => Applicative (ConstDeclare env r) where   pure _ = ConstDeclare $ pure mempty   (ConstDeclare f) <*> (ConstDeclare a) = ConstDeclare $ do@@ -43,6 +54,7 @@     a' <- a     pure $ f' <> a' +-- | Contravariant ignores argument. instance Contravariant (ConstDeclare env r) where   contramap _ (ConstDeclare d) = ConstDeclare d @@ -53,179 +65,282 @@     pure $ l' <> r'   conquer = ConstDeclare $ pure mempty -newtype ObjectSchema a-  = ObjectSchema-  { getObjectSchema-    :: Declare (Definitions Schema) Schema-  } deriving (Functor, Applicative, Contravariant, Divisible) via (ConstDeclare (Definitions Schema) Schema)+data PropertyDeclare = PropertyDeclare+  { requiredProperties :: [T.Text],+    propertyTypes :: InsOrd.InsOrdHashMap T.Text (Referenced Schema)+  }+  deriving (Show, Generic) +instance Semigroup PropertyDeclare where+  (PropertyDeclare r t) <> (PropertyDeclare r' t') =+    PropertyDeclare+      (r <> r')+      (t <> t')++instance Monoid PropertyDeclare where+  mempty = PropertyDeclare mempty mempty++addDescription ::+  T.Text ->+  Referenced Schema ->+  Referenced Schema+addDescription text = \case+  Ref ref ->+    Inline $+      #_schemaDescription ?~ text $+        #_schemaOneOf ?~ [Ref ref] $+          mempty+  Inline sc -> Inline $ case sc ^. #_schemaDescription of+    Nothing -> #_schemaDescription ?~ text $ sc+    Just txt ->+      #_schemaDescription ?~ text $+        #_schemaOneOf ?~ [Inline sc] $+          mempty++newtype ObjectSchema a = ObjectSchema+  { getObjectSchema ::+      Declare (Definitions Schema) PropertyDeclare+  }+  deriving (Functor, Applicative, Contravariant, Divisible) via (ConstDeclare (Definitions Schema) PropertyDeclare)+ instance JSONObjectParser ObjectSchema where+  parseFieldWithDefault key = \prop _ -> ObjectSchema $ do+    r <- getRefDef $ getJSONSchema prop+    pure $ PropertyDeclare mempty $ InsOrd.singleton key r+  parseDescribeFieldWithDefault key description = \prop _ -> ObjectSchema $ do+    r <- getRefDef $ getJSONSchema prop+    pure $ PropertyDeclare mempty $ InsOrd.singleton key (addDescription description r)+  parseDescribeFieldWith key description = \prop -> ObjectSchema $ do+    r <- getRefDef $ getJSONSchema prop+    pure $ PropertyDeclare [key] $ InsOrd.singleton key (addDescription description r)   parseFieldWith t p = ObjectSchema $ do     r <- getRefDef (getJSONSchema p)-    pure $ (#_schemaProperties % at t ?~ r) mempty-  parseField-    :: forall a. FromJSON a-    => T.Text-    -> ObjectSchema a-  parseField label = ObjectSchema $ do-    ref <- getJSONRef (Proxy :: Proxy a)-    pure $ (#_schemaProperties % at label ?~ ref) mempty+    pure $ PropertyDeclare [t] $ InsOrd.singleton t r  instance JSONObjectSerializer ObjectSchema where-  writeField f w = ObjectSchema $ do+  serializeFieldWith f w = ObjectSchema $ do     r <- getRefDef (getJSONSchema w)-    pure $ (#_schemaProperties % at f ?~ r) mempty+    pure $ PropertyDeclare [f] $ InsOrd.singleton f r+  serializeJust f w = ObjectSchema $ do+    r <- getRefDef (getJSONSchema w)+    pure $ PropertyDeclare [] $ InsOrd.singleton f r -newtype TupleSchema a-  = TupleSchema-    { getTupleSchema-        :: Declare (Definitions Schema) [Referenced Schema]-    } deriving (Functor, Applicative, Contravariant, Divisible) via (ConstDeclare (Definitions Schema) [Referenced Schema])+newtype TupleSchema a = TupleSchema+  { getTupleSchema ::+      Declare (Definitions Schema) [Referenced Schema]+  }+  deriving (Functor, Applicative, Contravariant, Divisible) via (ConstDeclare (Definitions Schema) [Referenced Schema])  instance JSONTupleParser TupleSchema where   consumeItemWith p = TupleSchema $ do     r <- getRefDef $ getJSONSchema p     pure [r] -newtype JSONSchema a-  = JSONSchema+newtype JSONSchema a = JSONSchema   { getJSONSchema :: Declare (Definitions Schema) NamedSchema-  } deriving (Functor, Contravariant) via (ConstDeclare (Definitions Schema) NamedSchema)+  }+  deriving (Functor, Contravariant) via (ConstDeclare (Definitions Schema) NamedSchema)  instance Semigroup (JSONSchema a) where-  a <> b = JSONSchema . fmap unnamed $-    combineSchemas <$> getRefDef (getJSONSchema a) <*> getRefDef (getJSONSchema b)+  a <> b =+    JSONSchema . fmap unnamed $+      combineSchemas <$> getRefDef (getJSONSchema a) <*> getRefDef (getJSONSchema b)  instance Selectable JSONSchema where   giveUp = mempty   select _ (JSONSchema lhs) (JSONSchema rhs) = JSONSchema lhs <> JSONSchema rhs +-- | Empty instance: must be both a boolean and a text value, which is not possible (obviously!)+instance Monoid (JSONSchema a) where+  mempty = JSONSchema $ do+    t <- getJSONSchema parseText+    b <- getJSONSchema parseBool+    pure $ unnamed $ (#_schemaAllOf ?~ [Inline $ _namedSchemaSchema t, Inline $ _namedSchemaSchema b]) mempty++sameTypes :: Schema -> Schema -> Bool+sameTypes = (==) `on` (^. #_schemaType)++bothHaveEnum :: Schema -> Schema -> Bool+bothHaveEnum a b = enumValues a /= [] && enumValues b /= []++enumValues = (^. #_schemaEnum % non [])++combineInline :: Schema -> Schema -> Schema+combineInline a b+  | sameTypes a b && bothHaveEnum a b = (#_schemaEnum ?~ (enumValues a <> enumValues b)) a+  | otherwise =+    (#_schemaOneOf ?~ fromMaybe [Inline a] (_schemaOneOf a) <> fromMaybe [Inline b] (_schemaOneOf b)) mempty+ combineSchemas :: Referenced Schema -> Referenced Schema -> Schema combineSchemas = curry $ \case-  (Inline a, Inline b) ->-    (#_schemaOneOf ?~ fromMaybe [Inline a] (_schemaOneOf a) <> fromMaybe [Inline b] (_schemaOneOf b)) mempty+  (Inline a, Inline b) -> combineInline a b   (Inline a, Ref b) ->     (#_schemaOneOf ?~ fromMaybe [Inline a] (_schemaOneOf a) <> [Ref b]) mempty   (Ref a, Inline b) ->     (#_schemaOneOf ?~ [Ref a] <> fromMaybe [Inline b] (_schemaOneOf b)) mempty   (Ref a, Ref b) -> (#_schemaOneOf ?~ [Ref a, Ref b]) mempty --- | Empty instance: must be both a boolean and a text value, which is not possible (obviously!)-instance Monoid (JSONSchema a) where-  mempty = JSONSchema $ do-    t <- getJSONSchema parseText-    b <- getJSONSchema parseBool-    pure $ unnamed $ (#_schemaAllOf ?~ [Inline $ _namedSchemaSchema t, Inline $ _namedSchemaSchema b]) mempty--getJSONRef-  :: forall a. FromJSON a-  => Proxy a-  -> Declare (Definitions Schema) (Referenced Schema)+getJSONRef ::+  forall a.+  FromJSON a =>+  Proxy a ->+  Declare (Definitions Schema) (Referenced Schema) getJSONRef = getRefDef . getFromNamed -getRefDef-  :: Declare (Definitions Schema) NamedSchema-  -> Declare (Definitions Schema) (Referenced Schema)+getRefDef ::+  Declare (Definitions Schema) NamedSchema ->+  Declare (Definitions Schema) (Referenced Schema) getRefDef decl = case undeclare decl of-    NamedSchema (Just name) schema -> do-      known <- looks (InsOrd.member name)-      unless known $ do-        declare [(name, schema)]-        void decl-      return $ Ref (Reference name)-    _ -> Inline . _namedSchemaSchema <$> decl+  NamedSchema (Just name) schema -> do+    known <- looks (InsOrd.member name)+    unless known $ do+      declare [(name, schema)]+      void decl+    return $ Ref (Reference name)+  _ -> Inline . (^. #_namedSchemaSchema) <$> decl  onlyUnnamed :: Schema -> JSONSchema a onlyUnnamed a = JSONSchema $ pure $ NamedSchema Nothing a +encodeRefName :: T.Text -> T.Text+encodeRefName = decodeUtf8 . urlEncode False . encodeUtf8+ instance JSONTupleSerializer TupleSchema where-  writeItem s = TupleSchema $ do+  serializeItemWith s = TupleSchema $ do     r <- getRefDef $ getJSONSchema s     pure [r]  instance JSONParser JSONSchema where-  parseObject n f = JSONSchema $ do+  parseObject f = JSONSchema $ do     d <- getObjectSchema f-    pure $ NamedSchema (Just n) d+    pure $+      NamedSchema Nothing $+        mempty+          & (#_schemaType ?~ OpenApiObject)+            . (#_schemaProperties .~ (d ^. #propertyTypes))+            . (#_schemaRequired .~ (d ^. #requiredProperties))   parseDictionary inner = JSONSchema $ do     r <- getRefDef (getJSONSchema inner)-    pure $ unnamed $-      ( (#_schemaType ?~ OpenApiObject)-      . (#_schemaAdditionalProperties ?~ AdditionalPropertiesSchema r)-      ) mempty+    pure $+      unnamed $+        ( (#_schemaType ?~ OpenApiObject)+            . (#_schemaAdditionalProperties ?~ AdditionalPropertiesSchema r)+        )+          mempty   parseTuple parser = JSONSchema $ do     items <- getTupleSchema parser     pure $-      ( unnamed-      . (#_schemaType ?~ OpenApiArray)-      . (#_schemaItems ?~ OpenApiItemsArray items)-      ) mempty+      mempty+        & ( unnamed+              . (#_schemaType ?~ OpenApiArray)+              . (#_schemaItems ?~ OpenApiItemsArray items)+          )   parseArrayWith p = JSONSchema $ do     itemRef <- getRefDef (getJSONSchema p)     pure $       ( unnamed-      . (#_schemaType ?~ OpenApiArray)-      . (#_schemaItems ?~ OpenApiItemsObject itemRef)-      ) mempty-  parseArray-    :: forall a. (FromJSON a)-    => JSONSchema [a]+          . (#_schemaType ?~ OpenApiArray)+          . (#_schemaItems ?~ OpenApiItemsObject itemRef)+      )+        mempty+  parseArray ::+    forall a.+    (FromJSON a) =>+    JSONSchema [a]   parseArray = JSONSchema $ do     itemRef <- getRefDef $ getFromNamed (Proxy :: Proxy a)     pure $       ( unnamed-      . (#_schemaType ?~ OpenApiArray)-      . (#_schemaItems ?~ OpenApiItemsObject itemRef)-      ) mempty+          . (#_schemaType ?~ OpenApiArray)+          . (#_schemaItems ?~ OpenApiItemsObject itemRef)+      )+        mempty   parseNumber = onlyUnnamed $ (#_schemaType ?~ OpenApiNumber) mempty-  parseTextConstant t-    = void-    . onlyUnnamed-    . (#_schemaType ?~ OpenApiString)-    . (#_schemaEnum ?~ [Aeson.String t])-    $ mempty+  parseInteger = onlyUnnamed $ (#_schemaType ?~ OpenApiInteger) mempty+  parseTextConstant t =+    void+      . onlyUnnamed+      . (#_schemaType ?~ OpenApiString)+      . (#_schemaEnum ?~ [Aeson.String t])+      $ mempty   parseNull = onlyUnnamed $ (#_schemaType ?~ OpenApiNull) mempty-  parseText = onlyUnnamed $  (#_schemaType ?~ OpenApiString) mempty+  parseText = onlyUnnamed $ (#_schemaType ?~ OpenApiString) mempty   parseBool = onlyUnnamed $ (#_schemaType ?~ OpenApiBoolean) mempty   validateJSON (JSONSchema d) = JSONSchema d+  nameParser name = \schema -> JSONSchema $ do+    (NamedSchema _ schema) <- getJSONSchema schema+    pure $ NamedSchema (Just $ encodeRefName name) schema+  addFormat format =+    JSONSchema+      . fmap+        (#_namedSchemaSchema % #_schemaFormat ?~ format)+      . getJSONSchema  instance JSONSerializer JSONSchema where-  serializeObject t f = JSONSchema $ do+  serializeObject f = JSONSchema $ do     d <- getObjectSchema f-    pure $ NamedSchema (Just t) d+    pure $+      NamedSchema Nothing $+        mempty+          & (#_schemaType ?~ OpenApiObject)+            . (#_schemaProperties .~ (d ^. #propertyTypes))+            . (#_schemaRequired .~ (d ^. #requiredProperties))   serializeTuple t = JSONSchema $ do     items <- getTupleSchema t     pure $       ( unnamed-      . (#_schemaType ?~ OpenApiArray)-      . (#_schemaItems ?~ OpenApiItemsArray items)-      ) mempty+          . (#_schemaType ?~ OpenApiArray)+          . (#_schemaItems ?~ OpenApiItemsArray items)+      )+        mempty   serializeArray :: forall a. (ToJSON a) => JSONSchema [a]   serializeArray = JSONSchema $ do     itemRef <- getRefDef $ getToNamed (Proxy :: Proxy a)     pure $       ( unnamed-      . (#_schemaType ?~ OpenApiArray)-      . (#_schemaItems ?~ OpenApiItemsObject itemRef)-      ) mempty+          . (#_schemaType ?~ OpenApiArray)+          . (#_schemaItems ?~ OpenApiItemsObject itemRef)+      )+        mempty   serializeText = parseText   serializeBool = parseBool   serializeNumber = parseNumber   serializeDictionary ser = JSONSchema $ do     r <- getRefDef (getJSONSchema ser)-    pure $ unnamed $-      ( (#_schemaType ?~ OpenApiObject)-      . (#_schemaAdditionalProperties ?~ AdditionalPropertiesSchema r)-      ) mempty+    pure $+      unnamed $+        ( (#_schemaType ?~ OpenApiObject)+            . (#_schemaAdditionalProperties ?~ AdditionalPropertiesSchema r)+        )+          mempty   serializeNull =     case parseNull of       JSONSchema a -> JSONSchema a   serializeTextConstant t = let (JSONSchema a) = parseTextConstant t in JSONSchema a+  nameSerializer t = \ser -> JSONSchema $ do+    (NamedSchema _ s) <- getJSONSchema ser+    pure $ NamedSchema (Just $ encodeRefName t) s --- | Get documentation for a type that implements FromJSON+-- | Get documentation for a type that implements 'Jordan.FromJSON.Class.FromJSON', in the @ Declare @ environment.+--+-- This will be inline documention, IE, it will be named but not stored in the schema definitions. getFromNamed :: forall a. (FromJSON a) => Proxy a -> Declare (Definitions Schema) NamedSchema getFromNamed p = getJSONSchema (fromJSON :: JSONSchema a) --- | Get documentation for a type that implements ToJSON+-- | Get documention for a type that implements 'Jordan.FromJSON.Class.FromJSON'.+--+-- This will store the type in the schemas key of the schema definitions, and give back a reference to it.+getFromRef :: forall a. (FromJSON a) => Proxy a -> Declare (Definitions Schema) (Referenced Schema)+getFromRef = getRefDef . getFromNamed++-- | Get documentation for a type that implements 'Jordan.ToJSON.Class.ToJSON'.+--+-- This will be inline documentation, IE, it will be named but not stored in the schema definitions. getToNamed :: forall a. (ToJSON a) => Proxy a -> Declare (Definitions Schema) NamedSchema getToNamed p = getJSONSchema (toJSON :: JSONSchema a)++-- | Get documentation for a type that implements 'Jordan.ToJSON.Class.ToJSON'.+--+-- This will store the type in the schemas key of the schemas definitions, then give back a reference to it.+getToRef :: forall a. (ToJSON a) => Proxy a -> Declare (Definitions Schema) (Referenced Schema)+getToRef = getRefDef . getToNamed
test/Jordan/OpenAPI/SpecDefs.hs view
@@ -14,9 +14,9 @@   = Person   { firstName :: T.Text   , lastName :: T.Text+  , age :: Int   } deriving (Show, Generic)   deriving anyclass (ToJSON, FromJSON)-  data Managership   = Managership
test/JordanOpenApiSpec.hs view
@@ -1,68 +1,59 @@ {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-}-module Main-    where +module Main where++import Data.Aeson (encode)+import qualified Data.ByteString.Lazy as BS import qualified Data.HashMap.Strict.InsOrd as I+import Data.OpenApi import Data.OpenApi.Declare (Declare, evalDeclare, execDeclare) import Data.OpenApi.Internal-import Data.Proxy (Proxy(..))+import Data.Proxy (Proxy (..)) import Data.Text (Text)-import Jordan (FromJSON(..), ToJSON(..))-import Jordan.OpenAPI (getFromNamed, getToNamed)+import Jordan (FromJSON (..), ToJSON (..))+import Jordan.OpenAPI (JordanToJSONSchema, getFromNamed, getToNamed) import Jordan.OpenAPI.SpecDefs import Optics.Operators ((^.)) import Test.Hspec (Expectation, SpecWith, before, describe, hspec, it, shouldBe, shouldContain) -main = hspec $ do-  fileScenarios-  entryScenarios-  recursiveScenarios-  topLevelScenarios+main = do+  hspec $ do+    fileScenarios+    entryScenarios+    recursiveScenarios -shouldMakeNamedTo-  :: (ToJSON a)-  => Proxy a-  -> Text-  -> Expectation+shouldMakeNamedTo ::+  (ToJSON a) =>+  Proxy a ->+  Text ->+  Expectation shouldMakeNamedTo p@Proxy name =   (evalDeclare (getToNamed p) mempty ^. #_namedSchemaName) `shouldBe` Just name -shouldMakeUnnamed-  :: (ToJSON a)-  => Proxy a-  -> Expectation-shouldMakeUnnamed p@Proxy =-  (evalDeclare (getToNamed p) mempty ^. #_namedSchemaName) `shouldBe` Nothing--shouldDeclareTo-  :: (ToJSON a)-  => Proxy a-  -> Text-  -> Expectation+shouldDeclareTo ::+  (ToJSON a) =>+  Proxy a ->+  Text ->+  Expectation shouldDeclareTo p@Proxy name =   I.keys (execDeclare (getToNamed p) mempty) `shouldContain` [name]  fileScenarios = describe "basic scenarios with file-like types" $ do   it "works with file" $ do-    (Proxy @File) `shouldMakeNamedTo` "Jordan.OpenAPI.SpecDefs.File.File.Output"+    (Proxy @File) `shouldMakeNamedTo` "Jordan.OpenAPI.SpecDefs.File"   it "works with directory" $ do-    (Proxy @Directory) `shouldMakeNamedTo` "Jordan.OpenAPI.SpecDefs.Directory.Directory.Output"+    (Proxy @Directory) `shouldMakeNamedTo` "Jordan.OpenAPI.SpecDefs.Directory"  entryScenarios = describe "bsaic scenarios with a directory-entry-like type" $ do   it "includes definition for a file" $ do-    (Proxy @FileEntry) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.File.File.Output"+    (Proxy @FileEntry) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.File"   it "includes definition for a directory" $ do-    (Proxy @FileEntry) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.Directory.Directory.Output"+    (Proxy @FileEntry) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.Directory"  recursiveScenarios = describe "scenarios with a recursive data type" $ do   it "contains the top-level type" $ do-    (Proxy @Managership) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.Managership.Managership.Output"+    (Proxy @Managership) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.Managership"   it "contains a nested type" $ do-    (Proxy @Managership) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.Person.Person.Output"--topLevelScenarios = describe "scenarios with some top-level sum type" $ do-  it "is not named" $ do-    shouldMakeUnnamed (Proxy @Rank)-+    (Proxy @Managership) `shouldDeclareTo` "Jordan.OpenAPI.SpecDefs.Person"