on develop help sign in
Adding namespaced resource actions
commit3908f1bc48f2bb623682c731a7436b049d7b925e authorBrendan Hay <brendan.g.hay@gmail.com> dateSun 27 Sep 2015, 14:51 (11 years ago) parenta5d48d5
9 files changed+137−94
gen/src/Gen/AST.hs+58−46 gen/src/Gen/Solve.hs+14−14 gen/src/Gen/Syntax.hs+6−7 gen/src/Gen/Tree.hs+4−1 gen/src/Gen/Types.hs+42−15 gen/src/Gen/Types/Id.hs+5−4 gen/src/Main.hs+1 gen/template/action.ede+7 gen/template/toc.ede−7
gen/src/Gen/AST.hs+58−46
@@ -32,6 +32,7 @@ import Data.Semigroup ((<>))
3232import qualified Data.Text as Text
3333import qualified Data.Text.Lazy as LText
3434import qualified Data.Text.Lazy.Builder as Build
35+import Data.Traversable (for)
3536import Gen.Formatting
3637import Gen.Solve
3738import Gen.Syntax
@@ -67,69 +68,64 @@ render svc = do
6768 branch p v = Branch (bname p v) v
6869
6970 Obj i rs -> do
70− p <- prefix k
71− Just <$> (Map.traverseWithKey (const . solve . mkProp k) rs >>= prod p)
72− where
73− prod p ts = Prod (dname k) (i ^. description)
74− <$> (objDecl k p ts >>= pp Indent)
75− <*> ctor p ts
76− <*> traverse (lens p) (Map.toList ts)
77− <*> traverse (pp Print) (jsonDecls k p ts)
78−
79− ctor p ts = Fun' (cname k) (Just help)
80− <$> (pp None (ctorSig k ts) <&> comments ts)
81− <*> pp Indent (ctorDecl k p ts)
71+ p <- prefix k
72+ ds <- derive k
73+ dd <- Map.traverseWithKey (const . solve . mkProp k) rs
74+ Just <$> prod k p i ds dd
75+
76+ prod :: Id -> Pre -> Info -> [Derive] -> Map Local Solved -> AST Data
77+ prod k p i ds ts = Prod (dname k) (i ^. description)
78+ <$> pp Indent (objDecl k p ds ts)
79+ <*> ctor
80+ <*> traverse lens (Map.toList ts)
81+ <*> traverse (pp Print) (jsonDecls k p ts)
82+ where
83+ ctor = Fun' (cname k) (Just help)
84+ <$> (pp None (ctorSig k ts) <&> comments ts)
85+ <*> pp Indent (ctorDecl k p ts)
8286
83− lens p (l, v) = Fun' (lname p l) (v ^. description)
84− <$> pp None (lensSig k p l v)
85− <*> pp Print (lensDecl p l v)
87+ lens (l, v) = Fun' (lname p l) (v ^. description)
88+ <$> pp None (lensSig k p l v)
89+ <*> pp Print (lensDecl p l v)
8690
87− help = rawHelpText $
88− sformat ("Creates a value of '" % fid %
89− "' with the minimum fields required to make a request.\n")
90− k
91+ help = rawHelpText $
92+ sformat ("Creates a value of '" % fid %
93+ "' with the minimum fields required to make a request.\n")
94+ k
9195
9296 api :: Resource -> AST API
93− api x = API n <$> pp Print (apiAlias n (nouns x)) <*> top x
97+ api x = do
98+ as <- Map.fromList <$> top x
99+ API n <$> pp Print (apiAlias n (Map.keys as))
100+ <*> pure as
94101 where
95102 n = name (Text.unpack (svcAbbrev svc))
96103
97− nouns = map nname . \case
98− Top rs -> Map.keys rs
99− Sub ms -> Map.keys ms
100−
101− top :: Resource -> AST [Action]
102104 top = \case
103105 Top rs -> traverse (uncurry sub) (Map.toList rs) <&> concat
104106 Sub ms -> traverse (uncurry (verb "")) (Map.toList ms)
105107
106− sub :: Local -> Resource -> AST [Action]
107108 sub l = \case
108− t@(Top rs) -> do
109− let k = nname l
110− t <- Action k Nothing
111− <$> pp Print (apiAlias k (nouns t))
112− as <- traverse (uncurry sub) (Map.toList rs) <&> concat
113− return (t : as)
114−
115− Sub ms -> do
116− let k = nname l
117− t <- Action k Nothing
118− <$> pp Print (apiAlias k (map (vname l) $ Map.keys ms))
119− as <- traverse (uncurry (verb l)) (Map.toList ms)
120− return (t : as)
121−
122− verb :: Local -> Local -> Method -> AST Action
123− verb p l m = Action (vname p l) (_mDescription m)
124− <$> pp Print (verbDecl svc p l m)
109+ Top rs -> traverse (uncurry sub) (Map.toList rs) <&> concat
110+ Sub ms -> traverse (uncurry (verb l)) (Map.toList ms)
111+
112+ verb p l m = do
113+ let (k, i) = vname p l
114+ s <- solve i
115+ Just d <- typ i (_schema s)
116+ fmap (k,) $
117+ Action k (actionNS svc p l) (_mDescription m)
118+ <$> pp Print (verbAlias svc k m)
119+ <*> pure d
125120
126121flatten :: Service (Fix Schema) Resource -> Service (Schema Id) Resource
127122flatten svc = svc { _svcSchemas = execState run mempty }
128123 where
129− run = mapM_ (uncurry top) (Map.toList (_svcSchemas svc))
124+ run = mapM_ (uncurry sch) (Map.toList (_svcSchemas svc))
125+ >> api (_svcApi svc)
130126
131− top :: Id -> Fix Schema -> State (Map Id (Schema Id)) Id
132− top n (Fix f) = go f >>= ins n
127+ sch :: Id -> Fix Schema -> State (Map Id (Schema Id)) Id
128+ sch n (Fix f) = go f >>= ins n
133129 where
134130 go = \case
135131 Obj i ps -> Obj i <$> Map.traverseWithKey (prop n) ps
@@ -154,6 +150,22 @@ flatten svc = svc { _svcSchemas = execState run mempty }
154150
155151 this = mkProp n l
156152
153+ api :: Resource -> State (Map Id (Schema Id)) ()
154+ api = \case
155+ Top rs -> mapM_ (uncurry sub) (Map.toList rs)
156+ Sub ms -> mapM_ (uncurry (verb "")) (Map.toList ms)
157+ where
158+ sub l = \case
159+ Top rs -> mapM_ (uncurry sub) (Map.toList rs)
160+ Sub ms -> mapM_ (uncurry (verb l)) (Map.toList ms)
161+
162+ -- FIXME: Global parameters
163+ verb p l m = do
164+ let (_, i) = vname p l
165+ rs <- Map.traverseWithKey (\k v -> prop i k (paramSchema v)) (_mParameters m)
166+ void . ins i $
167+ Obj (Info (_mDescription m) Nothing False Nothing) rs
168+
157169 ins :: Id -> Schema Id -> State (Map Id (Schema Id)) Id
158170 ins n x = do
159171 s <- gets (Map.lookup n)
gen/src/Gen/Solve.hs+14−14
@@ -137,25 +137,25 @@ derive :: Id -> AST [Derive]
137137derive k = loc "derive" k $ memo derived k go
138138 where
139139 go = \case
140− Obj _ rs -> foldM props base (Map.elems rs)
141− Arr _ r -> mappend monoid . intersect base <$> derive r
142− Enum {} -> pure (base <> enum)
143− Ref _ r -> pure base
144− Any _ -> pure base
140+ Obj _ rs -> foldM props dbase (Map.elems rs)
141+ Arr _ r -> mappend dmonoid . intersect dbase <$> derive r
142+ Enum {} -> pure denum
143+ Ref _ r -> pure dbase
144+ Any _ -> pure dbase
145145 Lit _ l -> pure $
146146 case l of
147− Text -> base <> [DOrd, DIsString]
148− Bool -> base <> enum
149− Time -> base
150− Date -> base
151− Nat -> base
152− _ -> base <> [DNum, DIntegral, DReal] <> enum
147+ Text -> dbase <> [DOrd, DIsString]
148+ Bool -> denum
149+ Time -> dbase
150+ Date -> dbase
151+ Nat -> dbase
152+ _ -> [DNum, DIntegral, DReal] <> denum
153153
154154 props ds x = intersect ds <$> derive x
155155
156− monoid = [DMonoid]
157− enum = [DOrd, DEnum]
158− base = [DEq, DRead, DShow, DData, DTypeable, DGeneric]
156+dmonoid = [DMonoid]
157+denum = [DOrd, DEnum] <> dbase
158+dbase = [DEq, DRead, DShow, DData, DTypeable, DGeneric]
159159
160160prefix :: Id -> AST Pre
161161prefix n = loc "prefix" n $ memo prefixed n typ
gen/src/Gen/Syntax.hs+6−7
@@ -40,8 +40,8 @@ apiAlias n ls = TypeDecl noLoc n [] alias
4040 x:xs -> foldl' (\l r -> TyInfix l (UnQual (sym ":<|>")) r) x xs
4141
4242-- type Method = :> ...
43−verbDecl :: Service s r -> Local -> Local -> Method -> Decl
44−verbDecl s p l m = TypeDecl noLoc (vname p l) [] alias
43+verbAlias :: Service s r -> Name -> Method -> Decl
44+verbAlias s n m = TypeDecl noLoc n [] alias
4545 where
4646 alias = foldr' (\l r -> TyInfix l (UnQual (sym ":>")) r) verb (path ++ qry)
4747
@@ -154,14 +154,16 @@ seqE :: Exp -> [Exp] -> Exp
154154seqE l [] = app (var "pure") l
155155seqE l (r:rs) = infixApp l "<$>" (infixE r "<*>" rs)
156156
157−objDecl :: Id -> Pre -> Map Local Solved -> AST Decl
158−objDecl n p rs = DataDecl noLoc arity [] d [] [conDecl d p rs] <$> derivings n
157+objDecl :: Id -> Pre -> [Derive] -> Map Local Solved -> Decl
158+objDecl n p ds rs = DataDecl noLoc arity [] d [] [conDecl d p rs] (der ds)
159159 where
160160 d = dname n
161161
162162 arity | Map.size rs == 1 = NewType
163163 | otherwise = DataType
164164
165+ der = map ((,[]) . unqual . drop 1 . show)
166+
165167conDecl :: Name -> Pre -> Map Local Solved -> QualConDecl
166168conDecl n p rs = QualConDecl noLoc [] [] body
167169 where
@@ -216,9 +218,6 @@ lensDecl p l s = sfun noLoc (lname p l) [] (UnGuardedRhs rhs) noBinds
216218 (paren (lamE noLoc [pvar "s", pvar "a"]
217219 (RecUpdate (var "s") [FieldUpdate (UnQual f) (var "a")])))
218220
219−derivings :: Id -> AST [Deriving]
220−derivings k = map ((,[]) . unqual . drop 1 . show) <$> derive k
221−
222221parameters :: [Solved] -> [Type]
223222parameters = map (external . _type) . filter (view required)
224223
gen/src/Gen/Tree.hs+4−1
@@ -27,6 +27,7 @@ import Control.Monad.Except
2727import Data.Aeson hiding (json)
2828import Data.Bifunctor
2929import Data.Foldable (foldr')
30+import qualified Data.HashMap.Strict as Map
3031import qualified Data.List.NonEmpty as NE
3132import Data.Monoid
3233import Data.Text (Text)
@@ -84,8 +85,10 @@ populate d Templates{..} l = (encodeString d :/) . dir lib <$> layout
8485 , mod' (typesNS s) (typeImports s) typesTemplate (pure svc)
8586 , mod' (prodNS s) (prodImports s) prodTemplate (pure svc)
8687 , mod' (sumNS s) (sumImports s) sumTemplate (pure svc)
87− ]
88+ ] ++ map action (svcActions s)
8889 where
90+ action n = mod' n (actionImports s) actionTemplate (pure svc)
91+
8992 svc = toJSON s
9093
9194 lib = fromText (_libName l)
gen/src/Gen/Types.hs+42−15
@@ -36,8 +36,9 @@ import Data.Aeson hiding (Bool, String)
3636import Data.Aeson.TH
3737import Data.Char
3838import Data.Function (on)
39+import qualified Data.HashMap.Strict as Map
3940import qualified Data.HashSet as Set
40−import Data.List (groupBy)
41+import Data.List (groupBy, sort)
4142import Data.List.NonEmpty (NonEmpty (..))
4243import qualified Data.List.NonEmpty as NE
4344import Data.Maybe
@@ -82,6 +83,7 @@ data Templates = Templates
8283 , typesTemplate :: Template
8384 , prodTemplate :: Template
8485 , sumTemplate :: Template
86+ , actionTemplate :: Template
8587 }
8688
8789newtype Version (v :: Symbol) = Version Text
@@ -271,6 +273,13 @@ data Param = Param
271273 , _prmLiteral :: !Lit
272274 }
273275
276+paramSchema :: Param -> Fix Schema
277+paramSchema p
278+ | _prmRepeated p = Fix $ Arr (_prmInfo p) lit
279+ | otherwise = lit
280+ where
281+ lit = Fix $ Lit (_prmInfo p) (_prmLiteral p)
282+
274283instance FromJSON Param where
275284 parseJSON = withObject "parameter" $ \o -> Param
276285 <$> o .: "location"
@@ -327,22 +336,33 @@ instance ToJSON Data where
327336 , "instances" .= is
328337 ]
329338
330−data Action = Action Name (Maybe Help) Rendered
339+data Action = Action
340+ { _actName :: Name
341+ , _actNS :: NS
342+ , _actHelp :: Maybe Help
343+ , _actAlias :: Rendered
344+ , _actData :: Data
345+ }
331346
332347instance ToJSON Action where
333− toJSON (Action n h d) = object
334− [ "name" .= Syn n
335− , "help" .= h
336− , "decl" .= d
348+ toJSON (Action n _ h a d) = object
349+ [ "name" .= Syn n
350+ , "help" .= h
351+ , "alias" .= a
352+ , "data" .= d
337353 ]
338354
339−data API = API Name Rendered [Action]
355+data API = API
356+ { _apiName :: Name
357+ , _apiDecl :: Rendered
358+ , _apiActions :: Map Name Action
359+ }
340360
341361instance ToJSON API where
342362 toJSON (API n d as) = object
343363 [ "name" .= Syn n
344364 , "decl" .= d
345− , "actions" .= as
365+ , "actions" .= Map.elems as
346366 ]
347367
348368data Method = Method
@@ -440,10 +460,14 @@ instance ToJSON (Service Data API) where
440460svcAbbrev :: Service s r -> Text
441461svcAbbrev = upperHead . renameAbbrev . _svcCanonicalName
442462
443−typeImports, prodImports, sumImports :: Service s r -> [NS]
444−typeImports s = ["Network.Google.Prelude", prodNS s, sumNS s]
445−prodImports s = ["Network.Google.Prelude", sumNS s]
446−sumImports _ = ["Network.Google.Prelude"]
463+svcActions :: Service s API -> [NS]
464+svcActions = map _actNS . Map.elems . _apiActions . _svcApi
465+
466+typeImports, prodImports, sumImports, actionImports :: Service s r -> [NS]
467+typeImports s = sort ["Network.Google.Prelude", prodNS s, sumNS s]
468+prodImports s = sort ["Network.Google.Prelude", sumNS s]
469+sumImports _ = sort ["Network.Google.Prelude"]
470+actionImports = typeImports
447471
448472tocNS, typesNS, prodNS, sumNS :: Service s r -> NS
449473tocNS s = NS $ "Network" : "Google" : Text.split (== '.') (_svcCanonicalName s)
@@ -451,11 +475,14 @@ typesNS = (<> "Types") . tocNS
451475prodNS = (<> "Product") . typesNS
452476sumNS = (<> "Sum") . typesNS
453477
454−exposedModules :: Service s r -> [NS]
455−exposedModules s = [tocNS s, typesNS s]
478+actionNS :: Service s r -> Local -> Local -> NS
479+actionNS s x y = tocNS s <> NS [upperHead (local x), upperHead (local y)]
480+
481+exposedModules :: Service s API -> [NS]
482+exposedModules s = sort (tocNS s : typesNS s : svcActions s)
456483
457484otherModules :: Service s r -> [NS]
458−otherModules s = [prodNS s, sumNS s]
485+otherModules s = sort [prodNS s, sumNS s]
459486
460487data Library = Library
461488 { _libName :: Text
gen/src/Gen/Types/Id.hs+5−4
@@ -45,10 +45,11 @@ import Language.Haskell.Exts.Syntax (Name)
4545nname :: Local -> Name
4646nname = name . Text.unpack . (<> "API") . upperHead . local
4747
48−vname :: Local -> Local -> Name
49−vname p l = name (f p <> f l)
48+vname :: Local -> Local -> (Name, Id)
49+vname p l = (dname n, n)
5050 where
51− f = Text.unpack . upperHead . local
51+ n = Free (Global (f p <> f l))
52+ f = upperHead . local
5253
5354dname, cname :: Id -> Name
5455dname = name . Text.unpack . upperHead . idToText
@@ -63,7 +64,7 @@ bname (Pre p) = name
6364fname, lname, pname :: Pre -> Local -> Name
6465fname = pre (Text.cons '_' . renameField)
6566lname = pre renameField
66−pname = pre (flip Text.snoc '_' . Text.cons 'p' . upperHead)
67+pname = pre (flip Text.snoc '_' . Text.cons 'p' . upperHead . renameField)
6768
6869pre :: (Text -> Text) -> Pre -> Local -> Name
6970pre f (Pre p) = name . Text.unpack . f . mappend p . upperHead . local
gen/src/Main.hs+1
@@ -138,6 +138,7 @@ main = do
138138 <*> load "types.ede"
139139 <*> load "prod.ede"
140140 <*> load "sum.ede"
141+ <*> load "action.ede"
141142 <* done
142143
143144 title "Selecting new service models..."
gen/template/action.edenew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE TypeOperators #-}
3+
4+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
5+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}
6+
7+{% include "_include/license.ede" %}
gen/template/toc.ede−7
@@ -48,10 +48,3 @@ TODO
4848-}
4949
5050{{ api.decl }}
51−{% for action in api.actions %}
52−
53−{% if action.value.help %}
54−{{ action.value.help }}
55−{% endif %}
56−{{ action.value.decl }}
57−{% endfor %}