@@ -0,0 +1,122 @@
2+{-# LANGUAGE DeriveLift #-}
3+{-# OPTIONS_GHC -fno-warn-orphans #-}
8+ , defaultDerivingOptions
9+ , derivingOptionsToJsonOptions
10+ , derivingOptionsToSchemaOptions
13+ , deriveToParamSchema
22+import Data.Aeson.TH as A
23+import Data.Aeson.Types
24+#if MIN_VERSION_th_abstraction(0,3,0)
27+import qualified Data.List as List
30+import Data.OpenApi hiding (prefix)
33+import Language.Haskell.TH
34+import Language.Haskell.TH.Datatype
35+import Language.Haskell.TH.Syntax
38+-- | derive JSON and openapi3 (ToSchema) instances
39+deriveApiInstances :: DerivingOptions -> Name -> Q [Dec]
41+deriveApiInstances opts tname = liftM2 (<>)
42+ (deriveJSON (derivingOptionsToJsonOptions opts) tname)
43+ (deriveToSchema opts tname)
45+deriveApiInstances opts tname =
46+ deriveJSON (derivingOptionsToJsonOptions opts) tname
49+-- We can't directly 'lift' Options into TH, so have to use this
50+data DerivingOptions = DerivingOptions
51+ { prefix :: Maybe String
52+ -- ^ Optional prefix to strip from constructors and field labels
54+ -- ^ Whether to snake constructors and field labels
55+ -- Applied after stripping prefix
56+ , unwrapUnaryRecords :: Bool
57+ , sumEncoding :: SumEncoding
60+deriving instance Lift SumEncoding
62+defaultDerivingOptions :: DerivingOptions
63+defaultDerivingOptions = DerivingOptions
66+ , unwrapUnaryRecords = True
67+ , sumEncoding = defaultTaggedObject }
69+derivingOptionsToJsonOptions :: DerivingOptions -> Options
70+derivingOptionsToJsonOptions DerivingOptions{..} = defaultOptions
71+ { fieldLabelModifier = snaked . stripped
72+ , constructorTagModifier = snaked . stripped
74+ , unwrapUnaryRecords }
76+ snaked = if snake then camelTo2 '_' else id
77+ stripped = maybe id stripPrefix prefix
80+derivingOptionsToSchemaOptions :: DerivingOptions -> SchemaOptions
81+derivingOptionsToSchemaOptions = fromAesonOptions . derivingOptionsToJsonOptions
83+deriveToParamSchema :: DerivingOptions -> Name -> Q [Dec]
84+deriveToParamSchema opts tname = do
86+ body = AppE (VarE 'genericToParamSchema) <$>
87+ appE (pure $ VarE 'derivingOptionsToSchemaOptions) (lift opts)
90+ (pure $ ConT ''ToParamSchema `AppT` ConT tname)
91+ [ funD 'toParamSchema $ pure $ clause [] (normalB body) [] ]
93+deriveToSchema :: DerivingOptions -> Name -> Q [Dec]
94+deriveToSchema opts tname = do
95+ tinfo <- reifyDatatype tname
97+ tvars = datatypeVars tinfo
98+#if MIN_VERSION_th_abstraction(0,3,0)
103+ [ConT ''Typeable `AppT` var, ConT ''ToSchema `AppT` var]
104+ body = AppE (VarE 'genericDeclareNamedSchema) <$>
105+ appE (pure $ VarE 'derivingOptionsToSchemaOptions) (lift opts)
108+ (pure $ ConT ''ToSchema `AppT` datatypeType tinfo)
109+ [ funD 'declareNamedSchema $ pure $ clause [] (normalB body) [] ]
112+deriveApiFromJSON :: DerivingOptions -> Name -> Q [Dec]
113+deriveApiFromJSON = deriveFromJSON . derivingOptionsToJsonOptions
115+deriveApiToJSON :: DerivingOptions -> Name -> Q [Dec]
116+deriveApiToJSON = deriveToJSON . derivingOptionsToJsonOptions
118+generateParseJSON :: DerivingOptions -> Name -> Q Exp
119+generateParseJSON = mkParseJSON . derivingOptionsToJsonOptions
121+stripPrefix :: String -> String -> String
122+stripPrefix pfx = fromMaybe <*> List.stripPrefix pfx