on develop help sign in
Merge pull request #294 from reflex-frp/prerender-lift-constraints

Lift Prerender method constraints onto class instead

commitc802e28f1c3636f35317c8a6672b368b64ecb755 authorRyan Trinkle <ryan.trinkle@gmail.com> dateWed 8 May 2019, 10:34 (7 years ago) parent0fefa3eeedf879
4 files changed+116−15
reflex-dom-core/reflex-dom-core.cabal+1 reflex-dom-core/src/Foreign/JavaScript/TH.hs+4−2 reflex-dom-core/src/Reflex/Dom/Prerender.hs+105−10 reflex-dom-core/test/hydration.hs+6−3
reflex-dom-core/reflex-dom-core.cabal+1
@@ -166,6 +166,7 @@ test-suite hydration
166166 , filepath
167167 , ghcjs-dom
168168 , hspec
169+ , hspec-core
169170 , hspec-webdriver
170171 , http-types
171172 , HUnit
reflex-dom-core/src/Foreign/JavaScript/TH.hs+4−2
@@ -289,10 +289,12 @@ class Monad m => MonadJS x m | m -> x where
289289 getJSProp :: String -> JSRef x -> m (JSRef x)
290290 withJSNode :: Node -> (JSRef x -> m r) -> m r
291291
292+type HasJS' = HasJS JS'
293+
292294#ifdef ghcjs_HOST_OS
293295
294296data JSCtx_IO
295−type HasJS' = HasJS JSCtx_IO
297+type JSX = JSCtx_IO
296298
297299instance MonadIO m => HasJS JSCtx_IO (WithJSContextSingleton x m) where
298300 type JSX (WithJSContextSingleton x m) = IO
@@ -343,7 +345,7 @@ foreign import javascript unsafe "function(){ return $1(arguments); }" funWithAr
343345#else
344346
345347data JSCtx_JavaScriptCore x
346−type HasJS' = HasJS (JSCtx_JavaScriptCore ())
348+type JS' = JSCtx_JavaScriptCore ()
347349
348350instance IsJSContext (JSCtx_JavaScriptCore x) where
349351 newtype JSRef (JSCtx_JavaScriptCore x) = JSRef_JavaScriptCore { unJSRef_JavaScriptCore :: JSVal }
reflex-dom-core/src/Reflex/Dom/Prerender.hs+105−10
@@ -1,8 +1,9 @@
11{-# LANGUAGE ConstraintKinds #-}
2−{-# LANGUAGE EmptyDataDecls #-}
2+{-# LANGUAGE EmptyCase #-}
33{-# LANGUAGE FlexibleContexts #-}
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE FunctionalDependencies #-}
6+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
67{-# LANGUAGE LambdaCase #-}
78{-# LANGUAGE OverloadedStrings #-}
89{-# LANGUAGE Rank2Types #-}
@@ -10,6 +11,7 @@
1011{-# LANGUAGE ScopedTypeVariables #-}
1112{-# LANGUAGE TypeFamilies #-}
1213{-# LANGUAGE UndecidableInstances #-}
14+{-# LANGUAGE UndecidableSuperClasses #-}
1315
1416-- | Render the first widget on the server, and the second on the client.
1517module Reflex.Dom.Prerender
@@ -19,12 +21,13 @@ module Reflex.Dom.Prerender
1921 , PrerenderBaseConstraints
2022 ) where
2123
22−import Control.Monad.Primitive (PrimMonad)
24+import Control.Monad.Primitive (PrimMonad(..))
2325import Control.Monad.Reader
2426import Control.Monad.Ref (MonadRef(..))
2527import Data.IORef (IORef, newIORef)
2628import Data.Semigroup (Semigroup)
2729import Data.Text (Text)
30+import Data.Void
2831import Foreign.JavaScript.TH
2932import GHCJS.DOM.Types (MonadJSM)
3033import Reflex hiding (askEvents)
@@ -33,7 +36,6 @@ import Reflex.Dom.Builder.Immediate
3336import Reflex.Dom.Builder.InputDisabled
3437import Reflex.Dom.Builder.Static
3538import Reflex.Host.Class
36−import Reflex.Requester.Base
3739import Data.IntMap.Strict (IntMap)
3840import qualified Data.IntMap.Strict as IntMap
3941
@@ -47,7 +49,6 @@ type PrerenderClientConstraint js t m =
4749 , DomRenderHook t m
4850 , HasDocument m
4951 , TriggerEvent t m
50− , Prerender js t m
5152 , PrerenderBaseConstraints js t m
5253 )
5354
@@ -75,16 +76,16 @@ type PrerenderBaseConstraints js t m =
7576-- hydration builder will run *both* widgets.
7677prerender_
7778 :: (Functor m, Reflex t, Prerender js t m)
78− => m () -> ((PrerenderClientConstraint js t (Client m)) => Client m ()) -> m ()
79+ => m () -> Client m () -> m ()
7980prerender_ server client = void $ prerender server client
8081
81−class Prerender js t m | m -> t js where
82+class (PrerenderClientConstraint js t (Client m), Client (Client m) ~ Client m, Prerender js t (Client m)) => Prerender js t m | m -> t js where
8283 -- | Monad in which the client widget is built
8384 type Client m :: * -> *
8485 -- | Render the first widget on the server, and the second on the client. The
8586 -- hydration builder will run *both* widgets, updating the result dynamic at
8687 -- switchover time.
87− prerender :: m a -> ((PrerenderClientConstraint js t (Client m)) => Client m a) -> m (Dynamic t a)
88+ prerender :: m a -> Client m a -> m (Dynamic t a)
8889
8990instance (ReflexHost t, Adjustable t m, PrerenderBaseConstraints js t m) => Prerender js t (HydrationDomBuilderT GhcjsDomSpace t m) where
9091 type Client (HydrationDomBuilderT GhcjsDomSpace t m) = HydrationDomBuilderT GhcjsDomSpace t m
@@ -129,10 +130,104 @@ instance (Adjustable t m, PrerenderBaseConstraints js t m, ReflexHost t) => Prer
129130 insertBefore df =<< deleteToPrerenderEnd doc
130131 holdDyn a0 a'
131132
132−data NoJavaScript -- This type should never have a HasJS instance
133+newtype UnrunnableT js t m a = UnrunnableT (ReaderT Void m a)
134+ deriving (Functor, Applicative, Monad, MonadTrans)
133135
134−instance (js ~ NoJavaScript, SupportsStaticDomBuilder t m) => Prerender js t (StaticDomBuilderT t m) where
135− type Client (StaticDomBuilderT t m) = HydrationDomBuilderT GhcjsDomSpace t m
136+unrunnable :: UnrunnableT js t m a
137+unrunnable = UnrunnableT $ ReaderT $ \case {}
138+
139+instance (Reflex t, Monad m) => DomBuilder t (UnrunnableT js t m) where
140+ type DomBuilderSpace (UnrunnableT js t m) = GhcjsDomSpace
141+ textNode _ = unrunnable
142+ commentNode _ = unrunnable
143+ element _ _ _ = unrunnable
144+ inputElement _ = unrunnable
145+ textAreaElement _ = unrunnable
146+ selectElement _ _ = unrunnable
147+ placeRawElement _ = unrunnable
148+ wrapRawElement _ _ = unrunnable
149+instance (Reflex t, Monad m) => NotReady t (UnrunnableT js t m) where
150+ notReadyUntil _ = unrunnable
151+ notReady = unrunnable
152+instance (Reflex t, Monad m) => Adjustable t (UnrunnableT js t m) where
153+ runWithReplace _ _ = unrunnable
154+ traverseIntMapWithKeyWithAdjust _ _ _ = unrunnable
155+ traverseDMapWithKeyWithAdjust _ _ _ = unrunnable
156+ traverseDMapWithKeyWithAdjustWithMove _ _ _ = unrunnable
157+instance (Reflex t, Monad m) => PerformEvent t (UnrunnableT js t m) where
158+ type Performable (UnrunnableT js t m) = UnrunnableT js t m
159+ performEvent _ = unrunnable
160+ performEvent_ _ = unrunnable
161+instance Monad m => MonadRef (UnrunnableT js t m) where
162+ type Ref (UnrunnableT js t m) = Ref IO
163+ newRef _ = unrunnable
164+ readRef _ = unrunnable
165+ writeRef _ _ = unrunnable
166+instance Monad m => HasDocument (UnrunnableT js t m) where
167+ askDocument = unrunnable
168+instance Monad m => HasJSContext (UnrunnableT js t m) where
169+ type JSContextPhantom (UnrunnableT js t m) = ()
170+ askJSContext = unrunnable
171+instance Monad m => HasJS JS' (UnrunnableT js t m) where
172+ type JSX (UnrunnableT js t m) = UnrunnableT js t m
173+ liftJS _ = unrunnable
174+instance Monad m => MonadJS JS' (UnrunnableT js t m) where
175+ runJS _ _ = unrunnable
176+ forkJS _ = unrunnable
177+ mkJSUndefined = unrunnable
178+ isJSNull _ = unrunnable
179+ isJSUndefined _ = unrunnable
180+ fromJSBool _ = unrunnable
181+ fromJSString _ = unrunnable
182+ fromJSArray _ = unrunnable
183+ fromJSUint8Array _ = unrunnable
184+ fromJSNumber _ = unrunnable
185+ withJSBool _ _ = unrunnable
186+ withJSString _ _ = unrunnable
187+ withJSNumber _ _ = unrunnable
188+ withJSArray _ _ = unrunnable
189+ withJSUint8Array _ _ = unrunnable
190+ mkJSFun _ = unrunnable
191+ freeJSFun _ = unrunnable
192+ setJSProp _ _ _ = unrunnable
193+ getJSProp _ _ = unrunnable
194+ withJSNode _ _ = unrunnable
195+instance Monad m => TriggerEvent t (UnrunnableT js t m) where
196+ newTriggerEvent = unrunnable
197+ newTriggerEventWithOnComplete = unrunnable
198+ newEventWithLazyTriggerWithOnComplete _ = unrunnable
199+instance Monad m => MonadReflexCreateTrigger t (UnrunnableT js t m) where
200+ newEventWithTrigger _ = unrunnable
201+ newFanEventWithTrigger _ = unrunnable
202+instance Monad m => MonadFix (UnrunnableT js t m) where
203+ mfix _ = unrunnable
204+instance Monad m => MonadHold t (UnrunnableT js t m) where
205+ hold _ _ = unrunnable
206+ holdDyn _ _ = unrunnable
207+ holdIncremental _ _ = unrunnable
208+ buildDynamic _ _ = unrunnable
209+ headE _ = unrunnable
210+instance Monad m => MonadSample t (UnrunnableT js t m) where
211+ sample _ = unrunnable
212+instance Monad m => MonadIO (UnrunnableT js t m) where
213+ liftIO _ = unrunnable
214+instance Monad m => MonadJSM (UnrunnableT js t m) where
215+ liftJSM' _ = unrunnable
216+instance (Reflex t, Monad m) => PostBuild t (UnrunnableT js t m) where
217+ getPostBuild = unrunnable
218+instance Monad m => PrimMonad (UnrunnableT js t m) where
219+ type PrimState (UnrunnableT js t m) = PrimState IO
220+ primitive _ = unrunnable
221+instance (Reflex t, Monad m) => DomRenderHook t (UnrunnableT js t m) where
222+ withRenderHook _ _ = unrunnable
223+ requestDomAction _ = unrunnable
224+ requestDomAction_ _ = unrunnable
225+instance (Reflex t, Monad m) => Prerender JS' t (UnrunnableT js t m) where
226+ type Client (UnrunnableT js t m) = UnrunnableT js t m
227+ prerender _ _ = unrunnable
228+
229+instance (SupportsStaticDomBuilder t m) => Prerender JS' t (StaticDomBuilderT t m) where
230+ type Client (StaticDomBuilderT t m) = UnrunnableT JS' t m
136231 prerender server _ = do
137232 _ <- commentNode $ CommentNodeConfig startMarker Nothing
138233 a <- server
reflex-dom-core/test/hydration.hs+6−3
@@ -35,7 +35,6 @@ import Data.GADT.Compare.TH
3535import Data.GADT.Show.TH
3636import Data.IORef (IORef)
3737import Data.Maybe
38−import Data.Monoid
3938import Data.Proxy
4039import Data.Text (Text)
4140import Language.Javascript.JSaddle (syncPoint, liftJSM)
@@ -54,6 +53,7 @@ import System.IO.Temp
5453import System.Process
5554import qualified Test.HUnit as HUnit (assertEqual, assertFailure)
5655import qualified Test.Hspec as H
56+import qualified Test.Hspec.Core.Spec as H
5757import Test.Hspec (xit)
5858import Test.Hspec.WebDriver hiding (runWD, click, uploadFile, WD)
5959import qualified Test.Hspec.WebDriver as WD
@@ -812,7 +812,7 @@ tests withDebugging wdConfig caps _selenium = do
812812 , el "span" . text <$> replace
813813 ]
814814 it "can be nested in postBuild widget" $ runWD $ do
815− replaceChan <- liftIO newChan
815+ replaceChan :: Chan Text <- liftIO newChan
816816 let setup = findElemWithRetry $ WD.ByTag "div"
817817 check ssr = do
818818 -- Check that the original element still exists and has the correct text
@@ -1153,6 +1153,9 @@ tests withDebugging wdConfig caps _selenium = do
11531153 xs <- WD.findElems (WD.ByTag "li")
11541154 checkInitialItems dm xs
11551155 pure xs
1156+ moveSpec
1157+ :: (DMap Key2 Identity -> (WD.Element -> Chan (PatchDMapWithMove Key2 Identity) -> WD ()) -> WD ())
1158+ -> H.SpecM (WdTestSession ()) ()
11561159 moveSpec testMove = do
11571160 it "can insert an item" $ runWD $ testMove (DMap.fromList [Key2_Int 1 ==> 1, Key2_Int 3 ==> 3]) $ \body chan -> do
11581161 shouldContainText (T.strip $ T.unlines ["i11","i33"]) body
@@ -1192,7 +1195,7 @@ tests withDebugging wdConfig caps _selenium = do
11921195 describe "hydration/immediate" $ moveSpec $ \initMap test -> do
11931196 chan <- liftIO newChan
11941197 replace <- liftIO newChan
1195− lock <- liftIO newEmptyMVar
1198+ lock :: MVar () <- liftIO newEmptyMVar
11961199 let check = do
11971200 liftIO $ do
11981201 writeChan replace ()