on master help sign in
monad is done
commit496563b58a0ea60fd3c3b4b202d66c9137c02fa3 authorAleksey Uymanov <s9gf4ult@gmail.com> dateFri 26 Feb 2021, 15:43 (6 years ago) parent12d42b9
5 files changed+85−41
openapi-diff.cabal+3 src/OpenAPI/Checker/Aux.hs+1−1 src/OpenAPI/Checker/Report.hs+8−2 src/OpenAPI/Checker/Validate.hs+40−24 src/OpenAPI/Checker/Validate/Monad.hs+33−14
openapi-diff.cabal+3
@@ -35,8 +35,11 @@ common common-options
3535 , containers
3636 , generic-monoid
3737 , insert-ordered-containers
38+ , lens
39+ , mtl
3840 , openapi3
3941 , text
42+ , transformers
4043
4144 default-extensions: ConstraintKinds
4245 , DataKinds
src/OpenAPI/Checker/Aux.hs+1−1
@@ -4,4 +4,4 @@ import Data.OpenApi.Internal
44
55-- | Megre servers from parent (like PathItem) and child (like Operation)
66mergeServers :: [Server] -> [Server] -> [Server]
7−mergeServers = (error "FIXME: not implemented")
7+mergeServers parent child = (error "FIXME: not implemented")
src/OpenAPI/Checker/Report.hs+8−2
@@ -20,9 +20,9 @@ data Status = Success | Fail Text
2020
2121type Path = FilePath -- From the library
2222
23−data ReportTree = ReportTree
23+newtype ReportTree = ReportTree
2424 { paths :: Map Path (Errorable PathItemTree)
25− } deriving (Eq, Ord, Show, Generic)
25+ } deriving (Eq, Ord, Show, Generic, Semigroup, Monoid)
2626
2727data PathItemTree = PathItemTree
2828 { operations :: Map OperationName (Errorable OperationTree)
@@ -47,6 +47,12 @@ data OperationName
4747data OperationTree = OperationTree
4848 deriving (Eq, Ord, Show, Generic)
4949
50+instance Semigroup OperationTree where
51+ _ <> _ = OperationTree
52+
53+instance Monoid OperationTree where
54+ mempty = OperationTree
55+
5056instance Nested OperationTree where
5157 type Parent OperationTree = PathItemTree
5258 type Key OperationTree = OperationName
src/OpenAPI/Checker/Validate.hs+40−24
@@ -1,6 +1,7 @@
11module OpenAPI.Checker.Validate where
22
33import Control.Monad
4+import Control.Monad.Reader
45import Data.Functor
56import Data.HashMap.Strict.InsOrd as InsMap
67import Data.HashSet.InsOrd as InsSet
@@ -14,38 +15,52 @@ import OpenAPI.Checker.Validate.Monad
1415reportCompat :: OpenApi -> OpenApi -> Report
1516reportCompat = error "FIXME: reportCompat not implemented"
1617
17−forwardCompatible :: OpenApi -> OpenApi -> ReportTree
18−forwardCompatible old new = fst $ runTreeM $ openApiCompatible old new
18+forwardCompatible :: OpenApi -> OpenApi -> Errorable ReportTree
19+forwardCompatible old new
20+ = fmap snd
21+ $ runTreeM emptyEnv
22+ $ openApiCompatible old new
1923
2024openApiCompatible :: OpenApi -> OpenApi -> TreeM ReportTree ()
21−openApiCompatible old new = void $ follow $
22− (InsMap.toList $ _openApiPaths old) <&> \(path, oldItem) ->
23− (path, checkItem path oldItem)
25+openApiCompatible old new = do
26+ local (const servers) $ do
27+ follow $ (InsMap.toList $ _openApiPaths old) <&> \(path, oldItem) ->
28+ (path, checkItem path oldItem)
2429 where
25− oldServers = _openApiServers old
26− newServers = _openApiServers new
30+ servers = Env
31+ { oldServers = _openApiServers old
32+ , newServers = _openApiServers new }
2733 checkItem path oldItem = do
2834 case (InsMap.lookup path $ _openApiPaths new) of
2935 Nothing -> treeError $ "Path deleted"
3036 Just newItem ->
31− pathItemsCompatible (oldServers, oldItem) (newServers, newItem)
37+ pathItemsCompatible oldItem newItem
38+
39+
40+mergeEnvServers :: [Server] -> [Server] -> TreeM t Env
41+mergeEnvServers olds news = do
42+ env <- ask
43+ return $ Env
44+ { oldServers = mergeServers (oldServers env) olds
45+ , newServers = mergeServers (newServers env) news }
3246
3347pathItemsCompatible
34− :: ([Server], PathItem)
35− -> ([Server], PathItem)
48+ :: PathItem
49+ -> PathItem
3650 -> TreeM PathItemTree ()
37−pathItemsCompatible (oldServers' , old) (newServers' , new) = void $ follow
38− [ (Get, go _pathItemGet)
39− , (Put, go _pathItemPut)
40− , (Post, go _pathItemPost)
41− , (Delete, go _pathItemDelete)
42− , (Options, go _pathItemOptions)
43− , (Head, go _pathItemHead)
44− , (Patch, go _pathItemPatch)
45− , (Trace, go _pathItemTrace) ]
51+pathItemsCompatible old new = do
52+ newEnv <- mergeEnvServers (_pathItemServers old) (_pathItemServers new)
53+ local (const newEnv) $ do
54+ follow
55+ [ (Get, go _pathItemGet)
56+ , (Put, go _pathItemPut)
57+ , (Post, go _pathItemPost)
58+ , (Delete, go _pathItemDelete)
59+ , (Options, go _pathItemOptions)
60+ , (Head, go _pathItemHead)
61+ , (Patch, go _pathItemPatch)
62+ , (Trace, go _pathItemTrace) ]
4663 where
47− oldServers = mergeServers oldServers' (_pathItemServers old)
48− newServers = mergeServers newServers' (_pathItemServers new)
4964 go :: (PathItem -> Maybe Operation) -> TreeM OperationTree ()
5065 go getOp = case getOp old of
5166 Nothing -> return ()
@@ -54,10 +69,11 @@ pathItemsCompatible (oldServers' , old) (newServers' , new) = void $ follow
5469 Nothing -> do
5570 -- Operation was in old schema, but no in new one.
5671 treeError "Operation was deleted. Old client may try to use it."
57− Just newOp -> operationsCompatible (oldServers, oldOp) (newServers, newOp)
72+ Just newOp ->
73+ operationsCompatible oldOp newOp
5874
5975operationsCompatible
60− :: ([Server], Operation)
61− -> ([Server], Operation)
76+ :: Operation
77+ -> Operation
6278 -> TreeM OperationTree ()
6379operationsCompatible = error "FIXME: operationsCompatible not implemented"
src/OpenAPI/Checker/Validate/Monad.hs+33−14
@@ -1,32 +1,51 @@
11module OpenAPI.Checker.Validate.Monad where
22
3−import Data.Text (Text)
3+import Control.Lens
4+import Control.Monad.Except
5+import Control.Monad.Trans.Except
6+import Control.Monad.Trans.Reader
7+import Control.Monad.Trans.State.Strict
8+import Data.Foldable
9+import Data.Functor.Identity
10+import Data.OpenApi.Internal
11+import Data.Text (Text)
12+import Data.Traversable
13+import GHC.Generics (Generic)
414
15+type TreeM t = ReaderT Env (StateT t Errorable)
516
6−data TreeM t a = TreeM
17+data Env = Env
18+ { oldServers :: [Server]
19+ , newServers :: [Server]
20+ } deriving (Eq, Generic)
721
8−instance Functor (TreeM t)
9−instance Applicative (TreeM t)
10−instance Monad (TreeM t)
22+emptyEnv :: Env
23+emptyEnv = Env [] []
1124
12−type Errorable = Either Text
25+type Errorable = Either Err
26+
27+type Err = Text
1328
1429-- | Class of trees nested into another trees
15−class Nested t where
30+class (Monoid (Parent t)) => Nested t where
1631 type Parent t
1732 type Key t
1833 nest :: Key t -> Errorable t -> Parent t
1934
20−runTreeM :: TreeM t a -> (t, a)
21−runTreeM = error "FIXME: runReportTree not implemented"
35+runTreeM :: (Monoid t) => Env -> TreeM t a -> Errorable (a, t)
36+runTreeM env ma = runStateT (runReaderT ma env) mempty
2237
2338-- | Throws error in current tree
24−treeError :: Text -> TreeM t a
25−treeError = error "FIXME: treeError not implemented"
39+treeError :: Err -> TreeM t a
40+treeError = throwError
2641
2742-- | Runs several computations in different paths in subtrees
2843follow
29− :: (Traversable f, Nested t)
44+ :: (Foldable f, Nested t, Monoid t)
3045 => f (Key t, TreeM t a)
31− -> TreeM (Parent t) (f a)
32−follow = error "FIXME: follow not implemented"
46+ -> TreeM (Parent t) ()
47+follow tree = do
48+ env <- ask
49+ for_ tree $ \(key, sub) -> do
50+ let p = nest key $ fmap snd $ runTreeM env sub
51+ id <>= p