{-# LANGUAGE TemplateHaskell            #-}
module Data.API.Tools.Lens
    ( lensTool
    , binary
    ) where

import           Data.API.Tools.Combinators
import           Data.API.Tools.Datatypes
import           Data.API.Types

import           Control.Lens


-- | Tool to make lenses for fields in generated types.
lensTool :: APITool
lensTool :: APITool
lensTool = Tool APINode -> APITool
apiDataTypeTool (Tool APINode -> APITool) -> Tool APINode -> APITool
forall a b. (a -> b) -> a -> b
$ (ToolSettings -> APINode -> Q [Dec]) -> Tool APINode
forall a. (ToolSettings -> a -> Q [Dec]) -> Tool a
mkTool ((ToolSettings -> APINode -> Q [Dec]) -> Tool APINode)
-> (ToolSettings -> APINode -> Q [Dec]) -> Tool APINode
forall a b. (a -> b) -> a -> b
$ \ ToolSettings
ts APINode
an ->
    if ToolSettings -> APINode -> Bool
ok ToolSettings
ts APINode
an then Name -> Q [Dec]
makeLenses (Name -> Q [Dec]) -> Name -> Q [Dec]
forall a b. (a -> b) -> a -> b
$ APINode -> Name
rep_type_nm APINode
an else [Dec] -> Q [Dec]
forall (m :: * -> *) a. Monad m => a -> m a
return []
  where
    -- Exclude newtypes if we are using smart constructors, because
    -- the lens can be used to bypass the invariant
    ok :: ToolSettings -> APINode -> Bool
ok ToolSettings
ts APINode
an | SpNewtype (SpecNewtype BasicType
_ (Just Filter
_)) <- APINode -> Spec
anSpec APINode
an = Bool -> Bool
not (ToolSettings -> Bool
newtypeSmartConstructors ToolSettings
ts)
             | Bool
otherwise                                       = Bool
True


$(makeLenses ''Binary)