deriving-openapi3 (empty) → 0.1.0.0
raw patch · 4 files changed
+205/−0 lines, 4 filesdep +aesondep +basedep +deriving-aeson
Dependencies added: aeson, base, deriving-aeson, lens, openapi3, text
Files
- Changelog.md +3/−0
- LICENSE +21/−0
- deriving-openapi3.cabal +42/−0
- src/Deriving/OpenApi.hs +139/−0
+ Changelog.md view
@@ -0,0 +1,3 @@+# 0.1.0.0++Initial release
+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2022 Ilya Kostyuchenko++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ deriving-openapi3.cabal view
@@ -0,0 +1,42 @@+cabal-version: 1.12+name: deriving-openapi3+version: 0.1.0.0+license: MIT+license-file: LICENSE+maintainer: Ilya Kostyuchenko <ilyakooo0@gmail.com>+homepage: https://github.com/ilyakooo0/deriving-openapi3#readme+bug-reports: https://github.com/ilyakooo0/deriving-openapi3/issues+synopsis: DerivingVia for OpenAPI 3+description: DerivingVia for OpenAPI 3+category: JSON, Generics, OpenAPI+build-type: Simple+extra-source-files: Changelog.md++source-repository head+ type: git+ location: https://github.com/ilyakooo0/deriving-openapi3++library+ exposed-modules: Deriving.OpenApi+ hs-source-dirs: src+ other-modules: Paths_deriving_openapi3+ default-language: Haskell2010+ default-extensions:+ AllowAmbiguousTypes ScopedTypeVariables KindSignatures DataKinds+ TypeOperators FlexibleInstances TypeApplications+ UndecidableInstances TypeFamilies PolyKinds OverloadedStrings+ DerivingStrategies DerivingVia FlexibleContexts++ ghc-options:+ -Weverything -Wno-star-is-type -Wno-unsafe+ -Wno-prepositive-qualified-module -Wno-safe+ -Wno-missing-safe-haskell-mode -Wno-missing-import-lists+ -Wno-implicit-prelude++ build-depends:+ aeson <1.6,+ base <4.15,+ deriving-aeson <0.3,+ lens <4.20,+ openapi3 <3.2,+ text <1.3
+ src/Deriving/OpenApi.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -Wno-orphans #-}++-- | __Example:__+--+-- >>> :set -XDerivingStrategies -XDerivingVia -XDeriveGeneric+--+-- >>> :{+-- data User = User+-- { userFirstName :: String,+-- userAge :: Maybe Integer+-- }+-- deriving stock (Generic)+-- deriving (FromJSON, ToJSON, ToSchema)+-- via CustomJSON+-- '[FieldLabelModifier '[StripPrefix "user", CamelToSnake], RejectUnknownFields]+-- User+-- showYaml = Data.ByteString.Char8.putStr . Data.Yaml.encode+-- :}+--+-- >>> showYaml $ toSchema (Proxy :: Proxy User)+-- type: object+-- properties:+-- first_name:+-- type: string+-- age:+-- type: integer+-- required:+-- - first_name+-- additionalProperties: false+module Deriving.OpenApi+ ( CustomOpenApi,+ DatatypeNameModifier,+ ToSchema,+ module Deriving.Aeson,+ )+where++import Control.Lens+import qualified Data.Aeson.Types as A+import Data.OpenApi+import Data.OpenApi.Internal.ParamSchema+import Data.OpenApi.Internal.Schema+import Data.Proxy+import Data.Text (Text)+import qualified Data.Text as T+import Data.Typeable+import Deriving.Aeson+import GHC.Generics+import GHC.TypeLits++data Description (desc :: Symbol) = Description++instance (AesonOptions xs) => AesonOptions (Description f ': xs) where+ aesonOptions = aesonOptions @xs++instance KnownSymbol t => OpenApiOptionModifier (Description t) where+ openApiSchemaModifier = schema . description <>~ Just (toTextLine @t)++toTextLine :: forall s. KnownSymbol s => Text+toTextLine = "\n\n" <> T.pack (symbolVal (Proxy @s))++-- $setup+-- >>> import qualified Data.Yaml+-- >>> import qualified Data.ByteString.Char8++type CustomOpenApi = CustomJSON++instance+ (OpenApiOptionModifier xs, GToSchema (Rep x), Generic x, Typeable x, Typeable xs, Typeable k) =>+ ToSchema (CustomJSON (xs :: k) x)+ where+ declareNamedSchema Proxy =+ openApiSchemaModifier @xs+ <$> genericDeclareNamedSchema (openApiOptionsModifier @xs defaultSchemaOptions) (Proxy @x)++instance+ (OpenApiOptionModifier xs, GToParamSchema (Rep x), Generic x) =>+ ToParamSchema (CustomJSON (xs :: k) x)+ where+ toParamSchema Proxy =+ genericToParamSchema (openApiOptionsModifier @xs defaultSchemaOptions) (Proxy @x)++class OpenApiOptionModifier x where+ openApiOptionsModifier :: SchemaOptions -> SchemaOptions+ openApiOptionsModifier = id+ openApiSchemaModifier :: NamedSchema -> NamedSchema+ openApiSchemaModifier = id++data DatatypeNameModifier t++instance (StringModifier f) => OpenApiOptionModifier (DatatypeNameModifier f) where+ openApiOptionsModifier o = o {datatypeNameModifier = getStringModifier @f}++instance (AesonOptions xs) => AesonOptions (DatatypeNameModifier f ': xs) where+ aesonOptions = aesonOptions @xs++-- deriving-aeson-based instances++instance OpenApiOptionModifier UnwrapUnaryRecords where+ openApiOptionsModifier o = o {unwrapUnaryRecords = True}++instance OpenApiOptionModifier OmitNothingFields++#if MIN_VERSION_deriving_aeson(0,2,4)+instance OpenApiOptionModifier RejectUnknownFields where+ openApiSchemaModifier = schema . additionalProperties .~ Just (AdditionalPropertiesAllowed False)+#endif++instance StringModifier f => OpenApiOptionModifier (FieldLabelModifier f) where+ openApiOptionsModifier o = o {fieldLabelModifier = getStringModifier @f}++instance StringModifier f => OpenApiOptionModifier (ConstructorTagModifier f) where+ openApiOptionsModifier o = o {constructorTagModifier = getStringModifier @f}++instance+ TypeError ('Text "deriving-openapi3 does not currently the `TagSingleConstructors` modifier.") =>+ OpenApiOptionModifier TagSingleConstructors++instance OpenApiOptionModifier NoAllNullaryToStringTag where+ openApiOptionsModifier o = o {allNullaryToStringTag = False}++instance (KnownSymbol t, KnownSymbol c) => OpenApiOptionModifier (SumTaggedObject t c) where+ openApiOptionsModifier o = o {sumEncoding = A.TaggedObject (symbolVal (Proxy @t)) (symbolVal (Proxy @c))}++instance OpenApiOptionModifier SumUntaggedValue where+ openApiOptionsModifier o = o {sumEncoding = A.UntaggedValue}++instance OpenApiOptionModifier SumObjectWithSingleField where+ openApiOptionsModifier o = o {sumEncoding = A.ObjectWithSingleField}++instance OpenApiOptionModifier SumTwoElemArray where+ openApiOptionsModifier o = o {sumEncoding = A.TwoElemArray}++instance OpenApiOptionModifier '[]++instance (OpenApiOptionModifier x, OpenApiOptionModifier xs) => OpenApiOptionModifier (x ': xs) where+ openApiOptionsModifier = openApiOptionsModifier @xs . openApiOptionsModifier @x+ openApiSchemaModifier = openApiSchemaModifier @xs . openApiSchemaModifier @x