diff --git a/docs/src/topic-guides/FormSerialization.purs b/docs/src/topic-guides/FormSerialization.purs index f0bf97b..5d632b1 100644 --- a/docs/src/topic-guides/FormSerialization.purs +++ b/docs/src/topic-guides/FormSerialization.purs @@ -3,7 +3,8 @@ module FormSerialization where import Prelude import Control.Monad.Error.Class (throwError) -import Control.Monad.Indexed ((:>>=), (:*>)) +import Control.Monad.Indexed ((:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(..)) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Eq (genericEq) @@ -69,19 +70,19 @@ onPost onPost = parseFromForm :>>= case _ of - Left err -> + Left err -> Ix.do writeStatus statusBadRequest - :*> closeHeaders - :*> respond (err <> "\n") + closeHeaders + respond (err <> "\n") Right (Order { beers, meal }) - | meal == Omnivore || meal == Carnivore -> + | meal == Omnivore || meal == Carnivore -> Ix.do writeStatus statusBadRequest - :*> closeHeaders - :*> respond "Sorry, we do not serve meat here.\n" - | otherwise -> + closeHeaders + respond "Sorry, we do not serve meat here.\n" + | otherwise -> Ix.do writeStatus statusBadRequest - :*> closeHeaders - :*> respond ("One " <> show meal <> " meal and " + closeHeaders + respond ("One " <> show meal <> " meal and " <> show beers <> " beers coming up!\n") -- end snippet onPost @@ -92,16 +93,16 @@ main = _.method <$> getRequestData :>>= case _ of Left POST -> onPost - Left method -> + Left method -> Ix.do ignoreBody - :*> writeStatus statusMethodNotAllowed - :*> closeHeaders - :*> respond ("Method not supported: " <> show method) - Right customMethod -> + writeStatus statusMethodNotAllowed + closeHeaders + respond ("Method not supported: " <> show method) + Right customMethod -> Ix.do ignoreBody - :*> writeStatus statusMethodNotAllowed - :*> closeHeaders - :*> respond ("Custom method not supported: " <> show customMethod) + writeStatus statusMethodNotAllowed + closeHeaders + respond ("Custom method not supported: " <> show customMethod) -- Let's run it. in runServer defaultOptionsWithLogging {} router diff --git a/docs/src/topic-guides/NodeReaderT.purs b/docs/src/topic-guides/NodeReaderT.purs index d12fb83..3a643d1 100644 --- a/docs/src/topic-guides/NodeReaderT.purs +++ b/docs/src/topic-guides/NodeReaderT.purs @@ -1,7 +1,7 @@ module NodeReaderT where import Prelude -import Control.Monad.Indexed ((:>>=), (:*>)) +import Control.Monad.Indexed.Qualified as Ix import Effect.Aff (Aff) import Effect (Effect) import Control.Monad.Reader (ReaderT, ask, runReaderT) @@ -21,10 +21,10 @@ runAppM = flip runReaderT { thingToSay: "Hello, ReaderT!" } main :: Effect Unit main = - let app = - lift' ask :>>= \config -> - writeStatus statusOK - :*> closeHeaders - :*> respond config.thingToSay + let app = Ix.do + config <- lift' ask + writeStatus statusOK + closeHeaders + respond config.thingToSay in runServer' defaultOptionsWithLogging {} runAppM app -- end snippet main diff --git a/docs/src/topic-guides/ReadBody.purs b/docs/src/topic-guides/ReadBody.purs index 5c06b46..335b878 100644 --- a/docs/src/topic-guides/ReadBody.purs +++ b/docs/src/topic-guides/ReadBody.purs @@ -2,7 +2,8 @@ module ReadBody where import Prelude -import Control.Monad.Indexed ((:>>=), (:*>)) +import Control.Monad.Indexed ((:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(..)) import Data.HTTP.Method (Method(..)) import Effect (Effect) @@ -25,17 +26,16 @@ onPost (Conn req BodyRead res ResponseEnded c) Unit -- start snippet onPost -onPost = - readBody :>>= - case _ of - "" -> +onPost = Ix.do + readBody :>>= case _ of + "" -> Ix.do writeStatus statusBadRequest - :*> closeHeaders - :*> respond "... anyone there?" - msg -> + closeHeaders + respond "... anyone there?" + msg -> Ix.do writeStatus statusBadRequest - :*> closeHeaders - :*> respond ("You said: " <> msg) + closeHeaders + respond ("You said: " <> msg) -- end snippet onPost main :: Effect Unit @@ -45,16 +45,16 @@ main = _.method <$> getRequestData :>>= case _ of Left POST -> onPost - Left method -> + Left method -> Ix.do ignoreBody - :*> writeStatus statusMethodNotAllowed - :*> closeHeaders - :*> respond ("Method not supported: " <> show method) - Right customMethod -> + writeStatus statusMethodNotAllowed + closeHeaders + respond ("Method not supported: " <> show method) + Right customMethod -> Ix.do ignoreBody - :*> writeStatus statusMethodNotAllowed - :*> closeHeaders - :*> respond ("Custom method not supported: " <> show customMethod) + writeStatus statusMethodNotAllowed + closeHeaders + respond ("Custom method not supported: " <> show customMethod) -- Let's run it. in runServer defaultOptionsWithLogging {} router diff --git a/examples/Authentication.purs b/examples/Authentication.purs index e99421c..2323f08 100644 --- a/examples/Authentication.purs +++ b/examples/Authentication.purs @@ -2,7 +2,7 @@ module Examples.Authentication where import Prelude -import Control.Monad.Indexed ((:>>=), (:*>)) +import Control.Monad.Indexed.Qualified as Ix import Effect.Aff (Aff) import Effect (Effect) import Data.Maybe (Maybe(Just, Nothing)) @@ -29,17 +29,17 @@ userFromBasicAuth = main :: Effect Unit main = let - myProfilePage = - getConn :>>= \conn -> + myProfilePage = Ix.do + conn <- getConn case conn.components.authentication of - User name → do + User name → Ix.do writeStatus statusOK - :*> contentType textHTML - :*> closeHeaders - :*> respond (render (p (text ("You are authenticated as " <> name <> ".")))) + contentType textHTML + closeHeaders + respond (render (p (text ("You are authenticated as " <> name <> ".")))) - app = do + app = Ix.do BasicAuth.withAuthentication userFromBasicAuth - :*> BasicAuth.authenticated "Authentication Example" myProfilePage + BasicAuth.authenticated "Authentication Example" myProfilePage components = { authentication: unit } in runServer defaultOptionsWithLogging components app diff --git a/examples/AuthenticationAndAuthorization.purs b/examples/AuthenticationAndAuthorization.purs index 5e1c852..928ac13 100644 --- a/examples/AuthenticationAndAuthorization.purs +++ b/examples/AuthenticationAndAuthorization.purs @@ -9,7 +9,8 @@ module Examples.AuthenticationAndAuthorization where import Prelude -import Control.Monad.Indexed ((:>>=), (:*>)) +import Control.Monad.Indexed ((:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(..)) import Data.HTTP.Method (Method(GET)) import Data.Maybe (Maybe(Nothing, Just)) @@ -47,11 +48,11 @@ htmlWithStatus (Conn req reqState res StatusLineOpen c) (Conn req reqState res ResponseEnded c) Unit -htmlWithStatus status x = +htmlWithStatus status x = Ix.do writeStatus status - :*> contentType textHTML - :*> closeHeaders - :*> respond (render x) + contentType textHTML + closeHeaders + respond (render x) -- Users have user names. @@ -78,11 +79,9 @@ profileHandler (Conn req reqState res StatusLineOpen { | AUTHENTICATION_ROWS (Maybe User) c }) (Conn req reqState res ResponseEnded { | AUTHENTICATION_ROWS (Maybe User) c }) Unit -profileHandler = - getConn :>>= \conn → - htmlWithStatus - statusOK - (view conn.components.authentication) +profileHandler = Ix.do + conn <- getConn + htmlWithStatus statusOK (view conn.components.authentication) where view = case _ of @@ -112,11 +111,9 @@ adminHandler (Conn req reqState res StatusLineOpen { | AUTHORIZATION_ROWS Admin + AUTHENTICATION_ROWS User c }) (Conn req reqState res ResponseEnded { | AUTHORIZATION_ROWS Admin + AUTHENTICATION_ROWS User c }) Unit -adminHandler = - getConn :>>= \conn → - htmlWithStatus - statusOK - (view conn.components.authentication) +adminHandler = Ix.do + conn <- getConn + htmlWithStatus statusOK (view conn.components.authentication) where view (User { name }) = section do diff --git a/examples/Cookies.purs b/examples/Cookies.purs index 580d5dc..4acb73b 100644 --- a/examples/Cookies.purs +++ b/examples/Cookies.purs @@ -1,7 +1,7 @@ module Examples.Cookies where import Prelude -import Control.Monad.Indexed ((:*>)) +import Control.Monad.Indexed.Qualified as Ix import Effect (Effect) import Hyper.Cookies (cookies) import Hyper.Node.Server (defaultOptionsWithLogging, runServer) @@ -10,8 +10,9 @@ import Hyper.Status (statusOK) main :: Effect Unit main = - let app = cookies - :*> writeStatus statusOK - :*> closeHeaders - :*> respond "Hello, Hyper!" + let app = Ix.do + cookies + writeStatus statusOK + closeHeaders + respond "Hello, Hyper!" in runServer defaultOptionsWithLogging { cookies: unit } app diff --git a/examples/FileServer.purs b/examples/FileServer.purs index c706178..ee42748 100644 --- a/examples/FileServer.purs +++ b/examples/FileServer.purs @@ -2,7 +2,7 @@ module Examples.FileServer where import Prelude -import Control.Monad.Indexed ((:*>)) +import Control.Monad.Indexed.Qualified as Ix import Effect (Effect) import Data.Tuple (Tuple(Tuple)) import Hyper.Node.FileServer (fileServer) @@ -14,9 +14,9 @@ import Node.Encoding (Encoding(UTF8)) main :: Effect Unit main = let - notFound = + notFound = Ix.do writeStatus statusNotFound - :*> headers [] - :*> respond (Tuple "

Not Found

" UTF8) + headers [] + respond (Tuple "

Not Found

" UTF8) app = fileServer "examples/FileServer" notFound in runServer defaultOptionsWithLogging {} app diff --git a/examples/FormParser.purs b/examples/FormParser.purs index 8269c43..ad3cd20 100644 --- a/examples/FormParser.purs +++ b/examples/FormParser.purs @@ -2,8 +2,8 @@ module Examples.FormParser where import Prelude -import Control.Bind.Indexed (ibind) -import Control.Monad.Indexed ((:>>=), (:*>)) +import Control.Monad.Indexed ((:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(Right, Left)) import Data.HTTP.Method (Method(..)) import Data.Maybe (Maybe(Nothing, Just)) @@ -52,11 +52,11 @@ main = (Conn HttpRequest reqState HttpResponse StatusLineOpen comp) (Conn HttpRequest reqState HttpResponse ResponseEnded comp) Unit - htmlWithStatus status x = + htmlWithStatus status x = Ix.do writeStatus status - :*> contentType textHTML - :*> closeHeaders - :*> respond (render x) + contentType textHTML + closeHeaders + respond (render x) handlePost :: forall comp . Middleware @@ -67,9 +67,9 @@ main = handlePost = parseForm :>>= case _ of - Left err -> do + Left err -> Ix.do liftEffect (log err) - :*> htmlWithStatus statusBadRequest + htmlWithStatus statusBadRequest (p (text "Bad request, invalid form.")) Right form -> case required "firstName" form of @@ -89,16 +89,16 @@ main = (Conn HttpRequest BodyUnread HttpResponse StatusLineOpen comp) (Conn HttpRequest BodyRead HttpResponse ResponseEnded comp) Unit - router = let bind = ibind in do + router = Ix.do reqData <- getRequestData case reqData.method of - Left GET -> do - _ <- ignoreBody + Left GET -> Ix.do + ignoreBody htmlWithStatus statusOK (renderNameForm Nothing) - Left POST -> do + Left POST -> Ix.do handlePost - method -> do - _ <- ignoreBody + method -> Ix.do + ignoreBody htmlWithStatus statusMethodNotAllowed (text ("Method not supported: " <> show method)) diff --git a/examples/HelloHyper.purs b/examples/HelloHyper.purs index 52101d8..c1e3f68 100644 --- a/examples/HelloHyper.purs +++ b/examples/HelloHyper.purs @@ -1,7 +1,7 @@ module Examples.HelloHyper where import Prelude -import Control.Monad.Indexed ((:*>)) +import Control.Monad.Indexed.Qualified as Ix import Effect (Effect) import Hyper.Node.Server (defaultOptionsWithLogging, runServer) import Hyper.Response (closeHeaders, respond, writeStatus) @@ -9,7 +9,8 @@ import Hyper.Status (statusOK) main :: Effect Unit main = - let app = writeStatus statusOK - :*> closeHeaders - :*> respond "Hello, Hyper!" + let app = Ix.do + writeStatus statusOK + closeHeaders + respond "Hello, Hyper!" in runServer defaultOptionsWithLogging {} app diff --git a/examples/NodeStreamRequest.purs b/examples/NodeStreamRequest.purs index abf3ddc..2a4f2fa 100644 --- a/examples/NodeStreamRequest.purs +++ b/examples/NodeStreamRequest.purs @@ -13,7 +13,8 @@ module Examples.NodeStreamRequest where import Prelude -import Control.Monad.Indexed (ibind, (:>>=)) +import Control.Monad.Indexed ((:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(..), either) import Data.HTTP.Method (Method(..)) import Effect (Effect) @@ -45,20 +46,17 @@ main = case _ of -- Only handle POST requests: - { method: Left POST } -> do + { method: Left POST } -> Ix.do streamBody \body -> logRequestBodyChunks body writeStatus statusOK closeHeaders respond "OK" -- Non-POST requests are not allowed: - { method } -> do + { method } -> Ix.do ignoreBody writeStatus statusMethodNotAllowed closeHeaders respond ("Method not allowed: " <> either show show method) - where - bind = ibind - discard = ibind in runServer defaultOptionsWithLogging {} app diff --git a/examples/NodeStreamResponse.purs b/examples/NodeStreamResponse.purs index 27491bf..4f1f29e 100644 --- a/examples/NodeStreamResponse.purs +++ b/examples/NodeStreamResponse.purs @@ -6,6 +6,7 @@ module Examples.NodeStreamResponse where import Prelude import Control.Monad.Indexed ((:*>)) +import Control.Monad.Indexed.Qualified as Ix import Effect.Aff as Aff import Effect.Aff.Class (class MonadAff, liftAff) import Effect (Effect) @@ -35,9 +36,9 @@ main = , Tuple 500 "Hyper\n" ] - app = do + app = Ix.do writeStatus statusOK - :*> closeHeaders - :*> streamMessages - :*> end + closeHeaders + streamMessages + end in runServer defaultOptions {} app diff --git a/examples/QualifiedDo.purs b/examples/QualifiedDo.purs index adf6a75..fa9f009 100644 --- a/examples/QualifiedDo.purs +++ b/examples/QualifiedDo.purs @@ -2,13 +2,13 @@ module Examples.QualifiedDo where import Prelude import Effect (Effect) -import Hyper.Middleware as Middleware +import Control.Monad.Indexed.Qualified as Ix import Hyper.Node.Server (defaultOptionsWithLogging, runServer) import Hyper.Response (closeHeaders, respond, writeStatus) import Hyper.Status (statusOK) main :: Effect Unit -main = runServer defaultOptionsWithLogging {} Middleware.do +main = runServer defaultOptionsWithLogging {} Ix.do writeStatus statusOK closeHeaders respond "Hello, Hyper!" diff --git a/examples/Sessions.purs b/examples/Sessions.purs index 55af46f..13dc565 100644 --- a/examples/Sessions.purs +++ b/examples/Sessions.purs @@ -2,6 +2,7 @@ module Examples.Sessions where import Prelude import Control.Monad.Indexed ((:*>), (:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Effect.Aff (launchAff) import Effect (Effect) import Effect.Class (liftEffect) @@ -31,38 +32,38 @@ main = void $ launchAff do , cookies: unit } - home = + home = Ix.do writeStatus statusOK - :*> contentType textHTML - :*> closeHeaders - :*> getSession :>>= - case _ of - Just (MySession { userId }) -> - lift' (log "Session") :*> - respond ("You are logged in as user " <> show userId <> ". " - <> "Logout if you're anxious.") - Nothing -> - lift' (log "No Session") :*> - respond "Login to start a session." + contentType textHTML + closeHeaders + getSession :>>= + case _ of + Just (MySession { userId }) -> + lift' (log "Session") :*> + respond ("You are logged in as user " <> show userId <> ". " + <> "Logout if you're anxious.") + Nothing -> + lift' (log "No Session") :*> + respond "Login to start a session." - login = + login = Ix.do redirect "/" - :*> saveSession (MySession { userId: 1 }) - :*> contentType textHTML - :*> closeHeaders - :*> end + saveSession (MySession { userId: 1 }) + contentType textHTML + closeHeaders + end - logout = + logout = Ix.do redirect "/" - :*> deleteSession - :*> closeHeaders - :*> end + deleteSession + closeHeaders + end - notFound = + notFound = Ix.do writeStatus statusNotFound - :*> contentType textHTML - :*> closeHeaders - :*> respond "Not Found" + contentType textHTML + closeHeaders + respond "Not Found" -- Simple router for this example. router = @@ -73,6 +74,6 @@ main = void $ launchAff do "/logout" -> logout _ -> notFound - app = + app = Ix.do cookies - :*> router + router diff --git a/examples/StateT.purs b/examples/StateT.purs index d8483e0..ac5a01a 100644 --- a/examples/StateT.purs +++ b/examples/StateT.purs @@ -1,12 +1,13 @@ module Examples.StateT where import Prelude -import Control.Monad.Indexed (ibind, (:*>)) -import Effect.Aff (Aff) -import Effect (Effect) -import Control.Monad.State (evalStateT, get, modify) + +import Control.Monad.Indexed.Qualified as Ix +import Control.Monad.State (evalStateT, modify, modify_) import Control.Monad.State.Trans (StateT) import Data.String (joinWith) +import Effect (Effect) +import Effect.Aff (Aff) import Hyper.Middleware (lift') import Hyper.Node.Server (defaultOptionsWithLogging, runServer') import Hyper.Response (closeHeaders, respond, writeStatus) @@ -22,16 +23,14 @@ main = let -- Our application just appends to the state in between -- some operations, then responds with the built up state... - app = do - _ <- lift' (modify (flip append ["I"])) - :*> writeStatus statusOK - :*> lift' (modify (flip append ["have"])) - :*> closeHeaders - :*> lift' (modify (flip append ["state."])) - - msgs ← lift' get - respond (joinWith " " msgs) + app = Ix.do + lift' (modify_ (flip append ["I"])) + writeStatus statusOK - where bind = ibind + lift' (modify_ (flip append ["have"])) + closeHeaders + + msgs <- lift' (modify (flip append ["state."])) + respond (joinWith " " msgs) in runServer' defaultOptionsWithLogging {} runAppM app diff --git a/src/Hyper/Authorization.purs b/src/Hyper/Authorization.purs index 8ea3bee..1d03067 100644 --- a/src/Hyper/Authorization.purs +++ b/src/Hyper/Authorization.purs @@ -1,6 +1,6 @@ module Hyper.Authorization where -import Control.Monad.Indexed (ibind) +import Control.Monad.Indexed.Qualified as Ix import Control.Monad (class Monad) import Data.Maybe (Maybe(Nothing, Just)) import Data.Unit (unit, Unit) @@ -35,16 +35,15 @@ authorized :: forall a m req reqState (res :: ResponseState -> Type) b c (Conn req reqState res StatusLineOpen { | AUTHORIZATION_ROWS Unit c }) (Conn req reqState res ResponseEnded { | AUTHORIZATION_ROWS Unit c }) Unit -authorized authorizer mw = do +authorized authorizer mw = Ix.do conn ← getConn auth ← lift' (authorizer conn) case auth of - Just a -> do - _ <- modifyConn (withAuthorization a) - _ <- mw + Just a -> Ix.do + modifyConn (withAuthorization a) + mw modifyConn (withAuthorization unit) - Nothing -> do - _ <- writeStatus statusForbidden - _ <- headers [] + Nothing -> Ix.do + writeStatus statusForbidden + headers [] respond "You are not authorized." - where bind = ibind diff --git a/src/Hyper/Cookies.purs b/src/Hyper/Cookies.purs index dead28f..0ed1407 100644 --- a/src/Hyper/Cookies.purs +++ b/src/Hyper/Cookies.purs @@ -17,7 +17,7 @@ module Hyper.Cookies import Prelude import Control.Monad.Error.Class (throwError) -import Control.Monad.Indexed (ibind) +import Control.Monad.Indexed.Qualified as Ix import Data.Array (catMaybes, cons, filter, foldMap, uncons, (:)) import Data.Either (Either) import Data.JSDate (JSDate, toUTCString) @@ -83,12 +83,11 @@ cookies :: forall m req reqState (res :: ResponseState -> Type) c (resState :: R (Conn req reqState res resState { | COOKIES_ROWS Unit c }) (Conn req reqState res resState { | COOKIES_ROWS' c }) Unit -cookies = do +cookies = Ix.do conn <- getConn { headers } <- getRequestData let cookies' = maybe (pure Object.empty) parseCookies (Object.lookup "cookie" headers) putConn conn { components { cookies = cookies' }} - where bind = ibind data SameSite = Strict | Lax newtype MaxAge = MaxAge Int diff --git a/src/Hyper/Form.purs b/src/Hyper/Form.purs index 09b0936..7e8eba4 100644 --- a/src/Hyper/Form.purs +++ b/src/Hyper/Form.purs @@ -13,7 +13,8 @@ module Hyper.Form import Prelude import Control.Monad.Error.Class (throwError) -import Control.Monad.Indexed (ibind, ipure, (:>>=)) +import Control.Monad.Indexed (ipure, (:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Array (head) import Data.Either (Either(..)) import Data.Maybe (Maybe(Just, Nothing), maybe) @@ -67,7 +68,7 @@ parseForm ∷ forall m req (res :: ResponseState -> Type) comp (resState :: Resp (Conn req BodyUnread res resState comp) (Conn req BodyRead res resState comp) (Either String Form) -parseForm = do +parseForm = Ix.do conn <- getConn { headers } <- getRequestData body <- readBody @@ -78,7 +79,6 @@ parseForm = do ipure (Form <$> parseUrlencoded body) Just mediaType -> ipure (Left ("Cannot parse media of type: " <> show mediaType)) - where bind = ibind class ToForm a where diff --git a/src/Hyper/Middleware.purs b/src/Hyper/Middleware.purs index 3240263..d5749f1 100644 --- a/src/Hyper/Middleware.purs +++ b/src/Hyper/Middleware.purs @@ -1,6 +1,5 @@ module Hyper.Middleware - ( module QualifiedDo - , Middleware(..) + ( Middleware(..) , evalMiddleware , hoistMiddleware , runMiddleware @@ -13,7 +12,6 @@ import Effect.Aff.Class (class MonadAff, liftAff) import Effect.Class (class MonadEffect, liftEffect) import Data.Tuple (Tuple(..), snd) import Hyper.Middleware.Class (class IxMonadMiddleware) -import Hyper.Middleware.QualifiedDo (bind, discard) as QualifiedDo newtype Middleware m i o a = Middleware (i -> m (Tuple a o)) @@ -26,7 +24,7 @@ evalMiddleware a s = map snd (runMiddleware a s) hoistMiddleware :: forall f g i o a. (f ~> g) -> Middleware f i o a -> Middleware g i o a hoistMiddleware f (Middleware k) = Middleware (f <<< k) -instance ixMonadMiddlewareMiddleware :: Applicative m ⇒ IxMonadMiddleware (Middleware m) where +instance ixMonadMiddlewareMiddleware :: Monad m ⇒ IxMonadMiddleware (Middleware m) where getConn = Middleware $ \c -> pure (Tuple c c) putConn c = Middleware $ \_ -> pure (Tuple unit c) diff --git a/src/Hyper/Middleware/Class.purs b/src/Hyper/Middleware/Class.purs index 236d665..eeaa665 100644 --- a/src/Hyper/Middleware/Class.purs +++ b/src/Hyper/Middleware/Class.purs @@ -3,12 +3,11 @@ module Hyper.Middleware.Class where import Control.Monad.Indexed (class IxMonad, (:>>=)) import Data.Unit (Unit) -class IxMonadMiddleware m where +class IxMonad m <= IxMonadMiddleware m where getConn ∷ ∀ i. m i i i putConn ∷ ∀ i o. o → m i o Unit modifyConn ∷ ∀ m i o - . IxMonad m - => IxMonadMiddleware m + . IxMonadMiddleware m => (i → o) -> m i o Unit modifyConn f = getConn :>>= \c -> putConn (f c) diff --git a/src/Hyper/Middleware/QualifiedDo.purs b/src/Hyper/Middleware/QualifiedDo.purs deleted file mode 100644 index a959599..0000000 --- a/src/Hyper/Middleware/QualifiedDo.purs +++ /dev/null @@ -1,10 +0,0 @@ -module Hyper.Middleware.QualifiedDo where - -import Control.Monad.Indexed (class IxBind, ibind) - -bind :: forall a b x y z m. IxBind m => m x y a -> (a -> m y z b) -> m x z b -bind = ibind - -discard :: forall a b x y z m. IxBind m => m x y a -> (a -> m y z b) -> m x z b -discard = ibind - diff --git a/src/Hyper/Node/BasicAuth.purs b/src/Hyper/Node/BasicAuth.purs index bf59c29..d37bb3d 100644 --- a/src/Hyper/Node/BasicAuth.purs +++ b/src/Hyper/Node/BasicAuth.purs @@ -1,7 +1,8 @@ module Hyper.Node.BasicAuth where import Control.Monad (class Monad, (>>=)) -import Control.Monad.Indexed (ibind, ipure) +import Control.Monad.Indexed (ipure) +import Control.Monad.Indexed.Qualified as Ix import Data.Functor ((<$>)) import Data.Maybe (Maybe(Nothing, Just)) import Data.Monoid ((<>)) @@ -40,7 +41,7 @@ withAuthentication (Conn req reqState res resState { | AUTHENTICATION_ROWS Unit c }) (Conn req reqState res resState { | AUTHENTICATION_ROWS (Maybe t) c }) Unit -withAuthentication mapper = do +withAuthentication mapper = Ix.do auth <- getAuth modifyConn (setAuthentication auth) where @@ -48,19 +49,18 @@ withAuthentication mapper = do case split (Pattern ":") s of [username, password] -> Just (Tuple username password) _ -> Nothing - getAuth = do + getAuth = Ix.do { headers } <- getRequestData case Object.lookup "authorization" headers of Nothing -> ipure Nothing Just header -> do case split (Pattern " ") header of - ["Basic", encoded] -> do + ["Basic", encoded] -> Ix.do decoded <- splitPair <$> decodeBase64 encoded case decoded of Just auth -> lift' (mapper auth) Nothing -> ipure Nothing parts -> ipure Nothing - bind = ibind authenticated :: forall m req reqState (res :: ResponseState -> Type) c b t @@ -78,17 +78,15 @@ authenticated (Conn req reqState res StatusLineOpen { | AUTHENTICATION_ROWS (Maybe t) c }) (Conn req reqState res ResponseEnded { | AUTHENTICATION_ROWS (Maybe t) c }) Unit -authenticated realm mw = do +authenticated realm mw = Ix.do conn ← getConn case conn.components.authentication of - Nothing -> do - _ <- writeStatus statusUnauthorized - _ <- writeHeader (Tuple "WWW-Authenticate" ("Basic realm=\"" <> realm <> "\"")) - _ <- closeHeaders + Nothing -> Ix.do + writeStatus statusUnauthorized + writeHeader (Tuple "WWW-Authenticate" ("Basic realm=\"" <> realm <> "\"")) + closeHeaders respond "Please authenticate." - Just auth -> do - _ <- modifyConn (setAuthentication auth) - _ <- mw + Just auth -> Ix.do + modifyConn (setAuthentication auth) + mw modifyConn (setAuthentication (Just auth)) - where - bind = ibind diff --git a/src/Hyper/Node/FileServer.purs b/src/Hyper/Node/FileServer.purs index 3b95ccb..d9d136b 100644 --- a/src/Hyper/Node/FileServer.purs +++ b/src/Hyper/Node/FileServer.purs @@ -2,12 +2,14 @@ module Hyper.Node.FileServer (fileServer) where import Prelude -import Control.Monad.Indexed (ibind, (:>>=)) +import Control.Monad.Indexed ((:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Array (last) import Data.Map (Map, fromFoldable, lookup) -import Data.Maybe (maybe) +import Data.Maybe (Maybe(..), maybe) import Data.String (Pattern(..), split) -import Data.Tuple (Tuple(Tuple)) +import Data.String.CodeUnits as String +import Data.Tuple (Tuple(Tuple), fst) import Effect.Aff.Class (liftAff, class MonadAff) import Effect.Class (liftEffect) import Hyper.Conn (Conn, StatusLineOpen, ResponseEnded, kind RequestState, kind ResponseState) @@ -139,20 +141,26 @@ serveFile' (Conn req reqState res StatusLineOpen c) (Conn req reqState res ResponseEnded c) Unit -serveFile' htaccessMap path = do +serveFile' htaccessMap path = Ix.do let - ext = last $ split (Pattern ".") path + splitAt :: Pattern -> String -> Tuple String String + splitAt pat@(Pattern p) str = + case String.indexOf pat str of + Just ix -> Tuple (String.take ix str) (String.drop (ix + String.length p) str) + Nothing -> Tuple str "" + + realPath = fst $ splitAt (Pattern "?") path + ext = last $ split (Pattern ".") realPath contentType = maybe "*/*" identity (ext >>= flip lookup htaccessMap) - buf <- lift' (liftAff (readFile path)) + buf <- lift' (liftAff (readFile realPath)) contentLength <- liftEffect (Buffer.size buf) - _ <- writeStatus statusOK - _ <- headers [ Tuple "Content-Type" (contentType <> "; charset=utf-8") + writeStatus statusOK + headers [ Tuple "Content-Type" (contentType <> "; charset=utf-8") , Tuple "Content-Length" (show contentLength) ] response <- toResponse buf - _ <- send response + send response end - where bind = ibind fileServer :: forall m req reqState (res :: ResponseState -> Type) c b @@ -194,7 +202,7 @@ fileServer' (Conn req reqState res StatusLineOpen c) (Conn req reqState res ResponseEnded c) Unit -fileServer' htaccessMap dir on404 = do +fileServer' htaccessMap dir on404 = Ix.do conn ← getConn { url } <- getRequestData serve (Path.concat [dir, url]) @@ -204,10 +212,8 @@ fileServer' htaccessMap dir on404 = do | isDirectory stats = serve (Path.concat [absolutePath, "index.html"]) | otherwise = on404 - serve absolutePath = do + serve absolutePath = Ix.do fExists ← lift' (liftAff (exists absolutePath)) if fExists then lift' (liftAff (stat absolutePath)) :>>= serveStats absolutePath else on404 - - bind = ibind diff --git a/src/Hyper/Node/Server.purs b/src/Hyper/Node/Server.purs index 00f1c9d..f4e4814 100644 --- a/src/Hyper/Node/Server.purs +++ b/src/Hyper/Node/Server.purs @@ -11,9 +11,9 @@ module Hyper.Node.Server import Prelude -import Control.Bind.Indexed (ibind) import Control.Monad.Error.Class (throwError) import Control.Monad.Indexed (ipure, (:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(..), either) import Data.HTTP.Method as Method import Data.Int as Int @@ -118,17 +118,17 @@ readBodyAsBuffer (HttpRequest request _) = do instance readableBodyHttpRequestString :: (Monad m, MonadAff m) => ReadableBody HttpRequest m String where - readBody = let bind = ibind in do + readBody = Ix.do buf <- readBody liftEffect $ Buffer.toString UTF8 buf instance readableBodyHttpRequestBuffer :: (Monad m, MonadAff m) => ReadableBody HttpRequest m Buffer where - readBody = let bind = ibind in do + readBody = Ix.do conn <- getConn body <- lift' (liftAff (readBodyAsBuffer conn.request)) let HttpRequest request reqData = conn.request - _ <- putConn (conn { request = HttpRequest request reqData }) + putConn (conn { request = HttpRequest request reqData }) ipure body instance streamableBodyHttpRequestReadable :: MonadAff m @@ -136,10 +136,10 @@ instance streamableBodyHttpRequestReadable :: MonadAff m HttpRequest m (Stream (read :: Stream.Read)) where - streamBody useStream = let bind = ibind in do + streamBody useStream = Ix.do conn <- getConn let HttpRequest request reqData = conn.request - _ <- lift' (useStream (HTTP.requestAsStream request)) + lift' (useStream (HTTP.requestAsStream request)) putConn (conn { request = HttpRequest request reqData }) newtype HttpResponse (resState :: ResponseState) = HttpResponse HTTP.Response @@ -211,34 +211,34 @@ unsafeEndResponse r = instance responseWriterHttpResponse :: MonadAff m => Response HttpResponse m (NodeResponse m) where - writeStatus status = let bind = ibind in do + writeStatus status = Ix.do conn <- getConn let HttpResponse r = conn.response - _ <- unsafeSetStatus status r - putConn (conn { response = HttpResponse r}) + unsafeSetStatus status r + putConn (conn { response = HttpResponse r }) - writeHeader header = let bind = ibind in do + writeHeader header = Ix.do conn <- getConn let HttpResponse r = conn.response - _ <- writeHeader' header r - putConn (conn { response = HttpResponse r}) + writeHeader' header r + putConn (conn { response = HttpResponse r }) - closeHeaders = let bind = ibind in do + closeHeaders = Ix.do conn <- getConn let HttpResponse r = conn.response - putConn (conn { response = HttpResponse r}) + putConn (conn { response = HttpResponse r }) - send f = let bind = ibind in do + send f = Ix.do conn <- getConn let HttpResponse r = conn.response - _ <- writeResponse r f - putConn (conn { response = HttpResponse r}) + writeResponse r f + putConn (conn { response = HttpResponse r }) - end = let bind = ibind in do + end = Ix.do conn <- getConn let HttpResponse r = conn.response - _ <- unsafeEndResponse r - putConn (conn { response = HttpResponse r}) + unsafeEndResponse r + putConn (conn { response = HttpResponse r }) mkHttpRequest :: HTTP.Request -> HttpRequest BodyUnread diff --git a/src/Hyper/Session.purs b/src/Hyper/Session.purs index caf2aa6..f8b2b7f 100644 --- a/src/Hyper/Session.purs +++ b/src/Hyper/Session.purs @@ -11,12 +11,15 @@ module Hyper.Session ) where import Prelude -import Data.NonEmpty as NonEmpty -import Foreign.Object as Object -import Control.Monad.Indexed (ibind, ipure, (:>>=)) + +import Control.Monad.Indexed (ipure, (:>>=)) +import Control.Monad.Indexed.Qualified as Ix import Data.Either (Either(..)) -import Data.Maybe (Maybe(Nothing, Just), maybe) +import Data.Foldable (for_) +import Data.Maybe (Maybe(Just, Nothing)) import Data.Newtype (class Newtype, unwrap) +import Data.NonEmpty as NonEmpty +import Foreign.Object as Object import Hyper.Conn (Conn, kind ResponseState, HeadersOpen) import Hyper.Cookies (COOKIES_ROWS', defaultCookieAttributes, maxAge, setCookie, SameSite(Lax)) import Hyper.Middleware (Middleware, lift') @@ -68,13 +71,12 @@ getSession (Conn req reqState res resState { | SESSION_ROWS store + COOKIES_ROWS' c }) (Conn req reqState res resState { | SESSION_ROWS store + COOKIES_ROWS' c }) (Maybe session) -getSession = do +getSession = Ix.do conn <- getConn sessionId <- currentSessionID case sessionId of Just id' -> lift' (get conn.components.sessions.store id') Nothing -> ipure Nothing - where bind = ibind saveSession :: forall m req reqState (res :: ResponseState -> Type) c b store session @@ -87,7 +89,7 @@ saveSession (Conn req reqState res HeadersOpen { | SESSION_ROWS store + COOKIES_ROWS' c }) (Conn req reqState res HeadersOpen { | SESSION_ROWS store + COOKIES_ROWS' c }) Unit -saveSession session = do +saveSession session = Ix.do conn <- getConn sessionId <- currentSessionID :>>= @@ -101,8 +103,6 @@ saveSession session = do conn.components.sessions.key (unwrap sessionId) (defaultCookieAttributes { sameSite=Just Lax, httpOnly=true }) - where - bind = ibind deleteSession :: forall m req reqState (res :: ResponseState -> Type) c b store session @@ -114,8 +114,9 @@ deleteSession (Conn req reqState res HeadersOpen { | SESSION_ROWS store + COOKIES_ROWS' c }) (Conn req reqState res HeadersOpen { | SESSION_ROWS store + COOKIES_ROWS' c }) Unit -deleteSession = do +deleteSession = Ix.do conn <- getConn - _ <- maybe (ipure unit) (lift' <<< delete conn.components.sessions.store) <$> currentSessionID + maybeId <- currentSessionID + for_ maybeId (lift' <<< delete conn.components.sessions.store) -- TODO: Better delete? setCookie conn.components.sessions.key "" (defaultCookieAttributes { maxAge=maxAge 0 }) diff --git a/src/Hyper/Test/TestServer.purs b/src/Hyper/Test/TestServer.purs index bdc63da..0fbf3f5 100644 --- a/src/Hyper/Test/TestServer.purs +++ b/src/Hyper/Test/TestServer.purs @@ -2,9 +2,9 @@ module Hyper.Test.TestServer where import Control.Alt ((<|>)) import Control.Applicative (pure) -import Control.Bind.Indexed (ibind) import Control.Monad (class Monad, void) import Control.Monad.Indexed (ipure, (:*>)) +import Control.Monad.Indexed.Qualified as Ix import Control.Monad.Writer (WriterT, execWriterT, tell) import Control.Monad.Writer.Class (class MonadTell) import Data.Either (Either(..)) @@ -51,14 +51,14 @@ defaultRequest = instance readableBodyStringBody :: Monad m => ReadableBody TestRequest m String where - readBody = let bind = ibind in do + readBody = Ix.do conn <- getConn let TestRequest rec = conn.request _ <- putConn (conn { request = TestRequest rec }) ipure rec.body instance requestTestRequest :: Monad m => Request TestRequest m where - getRequestData = let bind = ibind in do + getRequestData = Ix.do conn <- getConn let TestRequest r = conn.request _ <- putConn (conn { request = TestRequest r }) diff --git a/test/Hyper/Node/BasicAuthSpec.purs b/test/Hyper/Node/BasicAuthSpec.purs index f170bd7..d4caa53 100644 --- a/test/Hyper/Node/BasicAuthSpec.purs +++ b/test/Hyper/Node/BasicAuthSpec.purs @@ -1,7 +1,7 @@ module Hyper.Node.BasicAuthSpec where import Prelude -import Control.Monad.Indexed (ibind) +import Control.Monad.Indexed.Qualified as Ix import Data.Maybe (Maybe(Nothing, Just)) import Data.Newtype (unwrap, class Newtype) import Data.Tuple (fst, Tuple(Tuple)) @@ -58,12 +58,11 @@ spec = map unwrap response.components.authentication `shouldEqual` Just "user" describe "authenticated" do - let respondUserName = do + let respondUserName = Ix.do conn <- getConn - _ <- writeStatus statusOK - _ <- headers [] + writeStatus statusOK + headers [] respond (unwrap conn.components.authentication) - where bind = ibind it "runs the middleware with the authenticated user when available" do conn <- { request: TestRequest defaultRequest diff --git a/test/Hyper/Node/FileServerSpec.purs b/test/Hyper/Node/FileServerSpec.purs index a295ffc..3bfcf57 100644 --- a/test/Hyper/Node/FileServerSpec.purs +++ b/test/Hyper/Node/FileServerSpec.purs @@ -2,7 +2,7 @@ module Hyper.Node.FileServerSpec where import Prelude import Node.Buffer as Buffer -import Control.Monad.Indexed (ibind) +import Control.Monad.Indexed.Qualified as Ix import Effect.Aff.Class (class MonadAff) import Effect.Class (liftEffect) import Data.Maybe (Maybe(..)) @@ -34,12 +34,11 @@ serveFilesAndGet path = where app = fileServer "test/Hyper/Node/FileServerSpec" on404 - on404 = do + on404 = Ix.do body <- liftEffect (Buffer.fromString "Not Found" UTF8) - _ <- writeStatus statusNotFound - _ <- headers [] + writeStatus statusNotFound + headers [] respond body - where bind = ibind spec :: Spec Unit spec =