@@ -1,10 +1,16 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveFoldable #-}
3+{-# LANGUAGE DeriveFunctor #-}
2−{-# LANGUAGE DeriveGeneric #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveTraversable #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE FlexibleInstances #-}
8+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE KindSignatures #-}
9+{-# LANGUAGE KindSignatures #-}
4−{-# LANGUAGE LambdaCase #-}
10+{-# LANGUAGE LambdaCase #-}
5−{-# LANGUAGE OverloadedStrings #-}
11+{-# LANGUAGE OverloadedStrings #-}
6−{-# LANGUAGE RecordWildCards #-}
12+{-# LANGUAGE RecordWildCards #-}
7−{-# LANGUAGE TemplateHaskell #-}
13+{-# LANGUAGE TemplateHaskell #-}
9-- Module : Gen.Types
15-- Module : Gen.Types
10-- Copyright : (c) 2015 Brendan Hay
16-- Copyright : (c) 2015 Brendan Hay
@@ -22,8 +28,10 @@ import Control.Applicative
22import Data.Aeson hiding (String)
28import Data.Aeson hiding (String)
23import Data.Aeson.TH
29import Data.Aeson.TH
24import qualified Data.Attoparsec.Text as A
30import qualified Data.Attoparsec.Text as A
25import Data.Char
32import Data.Char
26import Data.Function (on)
33import Data.Function (on)
27import qualified Data.HashMap.Strict as Map
35import qualified Data.HashMap.Strict as Map
28import Data.List (groupBy, nub, sort)
36import Data.List (groupBy, nub, sort)
29import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
37import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
@@ -43,6 +51,8 @@ import GHC.Generics
43import GHC.TypeLits
51import GHC.TypeLits
44import Text.EDE (Template)
52import Text.EDE (Template)
54+newtype Fix f = Fix (f (Fix f))
46type Map = Map.HashMap
56type Map = Map.HashMap
47type Error = LText.Text
57type Error = LText.Text
48type Rendered = LText.Text
58type Rendered = LText.Text
@@ -128,6 +138,7 @@ deriveJSON (js "") ''Location
128data Info = Info
138data Info = Info
129 { _infoDescription :: Maybe Text
139 { _infoDescription :: Maybe Text
130 , _infoDefault :: Maybe Text
140 , _infoDefault :: Maybe Text
141+ , _infoRequired :: Maybe Bool
131 } deriving (Eq, Show)
142 } deriving (Eq, Show)
133deriveJSON (js "_info") ''Info
144deriveJSON (js "_info") ''Info
@@ -135,50 +146,83 @@ deriveJSON (js "_info") ''Info
137 | Boolean
148 | Boolean
138 deriving (Eq, Show)
150 deriving (Eq, Show)
140deriveToJSON (js "") ''Lit
152deriveToJSON (js "") ''Lit
157+ deriving (Eq, Show, Generic)
159+instance Semigroup Ref where
160+ a <> b = case (a, b) of
161+ (Opaque xs, Opaque ys) -> Opaque (xs <> ys)
162+ (Opaque xs, Direct y) -> Opaque (xs <> [y])
163+ (Direct x, Opaque ys) -> Opaque (x : ys)
164+ (Direct x, Direct y) -> Opaque [x, y]
166+instance Hashable Ref
168+instance FromJSON Ref where parseJSON = withText "ref" (pure . Direct)
169+instance ToJSON Ref where toJSON = toJSON . refToText
171+instance FromJSON a => FromJSON (Map Ref a) where
172+ parseJSON = fmap (Map.fromList . map (first Direct) . Map.toList) . parseJSON
174+instance ToJSON a => ToJSON (Map Ref a) where
175+ toJSON = toJSON . Map.fromList . map (first refToText) . Map.toList
177+refToText :: Ref -> Text
179+ Opaque xs -> Text.intercalate "." xs
182+ref :: Format a (Ref -> a)
183+ref = later (Build.fromText . refToText)
142−data Schema
185+data Schema a
143− = Obj Info (Map Text Schema)
186+ = Obj Info (Map Ref a)
144− | Arr Info Schema
187+ | Arr Info a
145 | Enum Info [Text] [Text]
188 | Enum Info [Text] [Text]
146 | Lit Info Lit
189 | Lit Info Lit
147− | Ref Text
190+ | Ref Ref
148 | Any' -- String or Number
191 | Any' -- String or Number
149− deriving (Eq, Show)
192+ deriving (Eq, Show, Functor, Foldable, Traversable)
151−instance FromJSON Schema where
194+instance FromJSON (Fix Schema) where
152− parseJSON = withObject "schema" $ \o -> schema o <|> ref o
195+ parseJSON = withObject "schema" $ \o -> Fix <$> (schema o <|> ref o)
154 schema o = do
197 schema o = do
155 i <- parseJSON (Object o)
198 i <- parseJSON (Object o)
156− t <- o .: "type" -- <|> fail ("Missing 'type' in " ++ show o)
157− case t of
199+ o .: "type" >>= \case
158 "object" -> Obj i <$> o .: "properties"
200 "object" -> Obj i <$> o .: "properties"
159 "array" -> Arr i <$> o .: "items"
201 "array" -> Arr i <$> o .: "items"
160 "string" -> enum i o <|> pure (Lit i String)
202 "string" -> enum i o <|> pure (Lit i String)
161 "boolean" -> pure (Lit i Boolean)
203 "boolean" -> pure (Lit i Boolean)
162 "any" -> pure Any'
204 "any" -> pure Any'
163− _ -> fail $
205+ e -> fail $
164− "Unable to parse Schema from: '" ++ Text.unpack t ++ "'"
206+ "Unable to parse Schema from: '" ++ Text.unpack e ++ "'"
166 enum i o = Enum i <$> o .: "enum" <*> o .: "enumDescriptions"
208 enum i o = Enum i <$> o .: "enum" <*> o .: "enumDescriptions"
168− ref o = Ref <$> o .: "$ref"
209+ ref o = Ref <$> o .: "$ref"
170deriveToJSON (js "") ''Schema
211deriveToJSON (js "") ''Schema
172−data Param = Param Location Schema
213+data Param a = Param Location a
173− deriving (Eq, Show)
214+ deriving (Eq, Show, Functor, Foldable, Traversable)
175−instance FromJSON Param where
216+instance FromJSON a => FromJSON (Param a) where
176 parseJSON = withObject "parameter" $ \o ->
217 parseJSON = withObject "parameter" $ \o ->
177 Param <$> o .: "location" <*> parseJSON (Object o)
218 Param <$> o .: "location" <*> parseJSON (Object o)
179deriveToJSON (js "") ''Param
220deriveToJSON (js "") ''Param
222+newtype Data = Data Rendered
223+ deriving (Eq, Show, ToJSON)
181−data Service = Service
225+data Service a = Service
182 { _svcLibrary :: Text
226 { _svcLibrary :: Text
183 , _svcTitle :: Text
227 , _svcTitle :: Text
184 , _svcName :: Text
228 , _svcName :: Text
@@ -196,39 +240,39 @@ data Service = Service
196 , _svcServicePath :: Text
240 , _svcServicePath :: Text
197 , _svcBatchPath :: Text
241 , _svcBatchPath :: Text
198 , _svcAuth :: Maybe Object
242 , _svcAuth :: Maybe Object
199− , _svcParameters :: Map Text Param
243+ , _svcParameters :: Map Text (Param a)
200− , _svcSchemas :: Map Text Schema
244+ , _svcSchemas :: Map Text a
201 , _svcResources :: Object
245 , _svcResources :: Object
202− } deriving (Show, Generic)
246+ } deriving (Generic)
204deriveFromJSON (js "_svc") ''Service
248deriveFromJSON (js "_svc") ''Service
206−instance ToJSON Service where
250+instance ToJSON (Service Data) where
207 toJSON s = Object (x <> y)
251 toJSON s = Object (x <> y)
209 Object x = genericToJSON (js "_svc") s
253 Object x = genericToJSON (js "_svc") s
210 Object y = object
254 Object y = object
211− [ "exposedModules" .= exposedModules s
255+ [ "exposedModules" .= exposedModules s
214−svcAbbrev :: Service -> Text
258+svcAbbrev :: Service a -> Text
215svcAbbrev = renameAbbrev . _svcTitle
259svcAbbrev = renameAbbrev . _svcTitle
217−typeImports :: Service -> [NS]
261+typeImports :: Service a -> [NS]
218typeImports _ = ["Network.Google.Prelude"]
262typeImports _ = ["Network.Google.Prelude"]
220−tocNS, typesNS :: Service -> NS
264+tocNS, typesNS :: Service a -> NS
221tocNS s = NS ["Network", "Google", svcAbbrev s]
265tocNS s = NS ["Network", "Google", svcAbbrev s]
222typesNS = (<> "Types") . tocNS
266typesNS = (<> "Types") . tocNS
224−exposedModules :: Service -> [NS]
268+exposedModules :: Service a -> [NS]
225exposedModules s = [tocNS s, typesNS s]
269exposedModules s = [tocNS s, typesNS s]
227data Library = Library
271data Library = Library
228 { _libName :: Text
272 { _libName :: Text
229 , _libTitle :: Text
273 , _libTitle :: Text
230 , _libVersions :: Versions
274 , _libVersions :: Versions
231− , _libServices :: NonEmpty Service
275+ , _libServices :: NonEmpty (Service Data)
234instance ToJSON Library where
278instance ToJSON Library where
@@ -241,7 +285,7 @@ instance ToJSON Library where
241 , "exposedModules" .= concatMap exposedModules (NE.toList _libServices)
285 , "exposedModules" .= concatMap exposedModules (NE.toList _libServices)
244−mergeLibraries :: Versions -> [Service] -> [Library]
288+mergeLibraries :: Versions -> [Service Data] -> [Library]
245mergeLibraries v = map go . groupBy (on (==) _svcLibrary)
289mergeLibraries v = map go . groupBy (on (==) _svcLibrary)
247 go [x] = mk x
291 go [x] = mk x