@@ -1,10 +1,16 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE DeriveGeneric #-}
3−{-# LANGUAGE KindSignatures #-}
4−{-# LANGUAGE LambdaCase #-}
5−{-# LANGUAGE OverloadedStrings #-}
6−{-# LANGUAGE RecordWildCards #-}
7−{-# LANGUAGE TemplateHaskell #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveFoldable #-}
3+{-# LANGUAGE DeriveFunctor #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveTraversable #-}
6+{-# LANGUAGE FlexibleContexts #-}
7+{-# LANGUAGE FlexibleInstances #-}
8+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9+{-# LANGUAGE KindSignatures #-}
10+{-# LANGUAGE LambdaCase #-}
11+{-# LANGUAGE OverloadedStrings #-}
12+{-# LANGUAGE RecordWildCards #-}
13+{-# LANGUAGE TemplateHaskell #-}
814
915-- Module : Gen.Types
1016-- Copyright : (c) 2015 Brendan Hay
@@ -22,8 +28,10 @@ import Control.Applicative
2228import Data.Aeson hiding (String)
2329import Data.Aeson.TH
2430import qualified Data.Attoparsec.Text as A
31+import Data.Bifunctor
2532import Data.Char
2633import Data.Function (on)
34+import Data.Hashable
2735import qualified Data.HashMap.Strict as Map
2836import Data.List (groupBy, nub, sort)
2937import Data.List.NonEmpty (NonEmpty (..), nonEmpty)
@@ -43,6 +51,8 @@ import GHC.Generics
4351import GHC.TypeLits
4452import Text.EDE (Template)
4553
54+newtype Fix f = Fix (f (Fix f))
55+
4656type Map = Map.HashMap
4757type Error = LText.Text
4858type Rendered = LText.Text
@@ -128,6 +138,7 @@ deriveJSON (js "") ''Location
128138data Info = Info
129139 { _infoDescription :: Maybe Text
130140 , _infoDefault :: Maybe Text
141+ , _infoRequired :: Maybe Bool
131142 } deriving (Eq, Show)
132143
133144deriveJSON (js "_info") ''Info
@@ -135,50 +146,83 @@ deriveJSON (js "_info") ''Info
135146data Lit
136147 = String
137148 | Boolean
149+ | Integer
138150 deriving (Eq, Show)
139151
140152deriveToJSON (js "") ''Lit
141153
142−data Schema
143− = Obj Info (Map Text Schema)
144− | Arr Info Schema
154+data Ref
155+ = Opaque [Text]
156+ | Direct Text
157+ deriving (Eq, Show, Generic)
158+
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]
165+
166+instance Hashable Ref
167+
168+instance FromJSON Ref where parseJSON = withText "ref" (pure . Direct)
169+instance ToJSON Ref where toJSON = toJSON . refToText
170+
171+instance FromJSON a => FromJSON (Map Ref a) where
172+ parseJSON = fmap (Map.fromList . map (first Direct) . Map.toList) . parseJSON
173+
174+instance ToJSON a => ToJSON (Map Ref a) where
175+ toJSON = toJSON . Map.fromList . map (first refToText) . Map.toList
176+
177+refToText :: Ref -> Text
178+refToText = \case
179+ Opaque xs -> Text.intercalate "." xs
180+ Direct n -> n
181+
182+ref :: Format a (Ref -> a)
183+ref = later (Build.fromText . refToText)
184+
185+data Schema a
186+ = Obj Info (Map Ref a)
187+ | Arr Info a
145188 | Enum Info [Text] [Text]
146189 | Lit Info Lit
147− | Ref Text
190+ | Ref Ref
148191 | Any' -- String or Number
149− deriving (Eq, Show)
192+ deriving (Eq, Show, Functor, Foldable, Traversable)
150193
151−instance FromJSON Schema where
152− parseJSON = withObject "schema" $ \o -> schema o <|> ref o
194+instance FromJSON (Fix Schema) where
195+ parseJSON = withObject "schema" $ \o -> Fix <$> (schema o <|> ref o)
153196 where
154197 schema o = do
155198 i <- parseJSON (Object o)
156− t <- o .: "type" -- <|> fail ("Missing 'type' in " ++ show o)
157− case t of
199+ o .: "type" >>= \case
158200 "object" -> Obj i <$> o .: "properties"
159201 "array" -> Arr i <$> o .: "items"
160202 "string" -> enum i o <|> pure (Lit i String)
161203 "boolean" -> pure (Lit i Boolean)
162204 "any" -> pure Any'
163− _ -> fail $
164− "Unable to parse Schema from: '" ++ Text.unpack t ++ "'"
205+ e -> fail $
206+ "Unable to parse Schema from: '" ++ Text.unpack e ++ "'"
165207
166208 enum i o = Enum i <$> o .: "enum" <*> o .: "enumDescriptions"
167−
168− ref o = Ref <$> o .: "$ref"
209+ ref o = Ref <$> o .: "$ref"
169210
170211deriveToJSON (js "") ''Schema
171212
172−data Param = Param Location Schema
173− deriving (Eq, Show)
213+data Param a = Param Location a
214+ deriving (Eq, Show, Functor, Foldable, Traversable)
174215
175−instance FromJSON Param where
216+instance FromJSON a => FromJSON (Param a) where
176217 parseJSON = withObject "parameter" $ \o ->
177218 Param <$> o .: "location" <*> parseJSON (Object o)
178219
179220deriveToJSON (js "") ''Param
180221
181−data Service = Service
222+newtype Data = Data Rendered
223+ deriving (Eq, Show, ToJSON)
224+
225+data Service a = Service
182226 { _svcLibrary :: Text
183227 , _svcTitle :: Text
184228 , _svcName :: Text
@@ -196,39 +240,39 @@ data Service = Service
196240 , _svcServicePath :: Text
197241 , _svcBatchPath :: Text
198242 , _svcAuth :: Maybe Object
199− , _svcParameters :: Map Text Param
200− , _svcSchemas :: Map Text Schema
243+ , _svcParameters :: Map Text (Param a)
244+ , _svcSchemas :: Map Text a
201245 , _svcResources :: Object
202− } deriving (Show, Generic)
246+ } deriving (Generic)
203247
204248deriveFromJSON (js "_svc") ''Service
205249
206−instance ToJSON Service where
250+instance ToJSON (Service Data) where
207251 toJSON s = Object (x <> y)
208252 where
209253 Object x = genericToJSON (js "_svc") s
210254 Object y = object
211− [ "exposedModules" .= exposedModules s
255+ [ "exposedModules" .= exposedModules s
212256 ]
213257
214−svcAbbrev :: Service -> Text
258+svcAbbrev :: Service a -> Text
215259svcAbbrev = renameAbbrev . _svcTitle
216260
217−typeImports :: Service -> [NS]
261+typeImports :: Service a -> [NS]
218262typeImports _ = ["Network.Google.Prelude"]
219263
220−tocNS, typesNS :: Service -> NS
264+tocNS, typesNS :: Service a -> NS
221265tocNS s = NS ["Network", "Google", svcAbbrev s]
222266typesNS = (<> "Types") . tocNS
223267
224−exposedModules :: Service -> [NS]
268+exposedModules :: Service a -> [NS]
225269exposedModules s = [tocNS s, typesNS s]
226270
227271data Library = Library
228272 { _libName :: Text
229273 , _libTitle :: Text
230274 , _libVersions :: Versions
231− , _libServices :: NonEmpty Service
275+ , _libServices :: NonEmpty (Service Data)
232276 }
233277
234278instance ToJSON Library where
@@ -241,7 +285,7 @@ instance ToJSON Library where
241285 , "exposedModules" .= concatMap exposedModules (NE.toList _libServices)
242286 ]
243287
244−mergeLibraries :: Versions -> [Service] -> [Library]
288+mergeLibraries :: Versions -> [Service Data] -> [Library]
245289mergeLibraries v = map go . groupBy (on (==) _svcLibrary)
246290 where
247291 go [x] = mk x