packages feed

miso 0.18.0.0 → 0.19.0.0

raw patch · 8 files changed

+139/−50 lines, 8 filesdep −hspecdep −hspec-corePVP ok

version bump matches the API change (PVP)

Dependencies removed: hspec, hspec-core

API changes (from Hackage documentation)

- Miso.Html.Element: b_ :: [Attribute actbon] -> [View actbon] -> View actbon
+ Miso.Html.Element: b_ :: [Attribute action] -> [View action] -> View action
- Miso.Html.Element: q_ :: [Attribute actqon] -> [View actqon] -> View actqon
+ Miso.Html.Element: q_ :: [Attribute action] -> [View action] -> View action
- Miso.Html.Element: u_ :: [Attribute actuon] -> [View actuon] -> View actuon
+ Miso.Html.Element: u_ :: [Attribute action] -> [View action] -> View action

Files

README.md view
@@ -27,6 +27,12 @@   </a> </p> +<p align="center">+  <a href="https://saucelabs.com/u/dmjio">+    <img src="https://saucelabs.com/browser-matrix/dmjio.svg" alt="Sauce Test Status"/>+  </a>+</p>+ **Miso** is a small "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming.  ## Table of Contents@@ -494,7 +500,7 @@  ## Isomorphic -Isomorphic javascript is a technique for increased SEO, code-sharing and perceived page load times. It works in two parts. First, the server sends a pre-rendered HTML body to the client's browser. Second, after the client javascript application loads, the pointers of the pre-rendered DOM are copied into the virtual DOM, and the application proceeds as normal. All subsequent page navigation is handled locally by the client, avoiding full-page postbacks as necessary.+[Isomorphic javascript](https://en.wikipedia.org/wiki/Isomorphic_JavaScript) is a technique for increased SEO, code-sharing and perceived page load times. It works in two parts. First, the server sends a pre-rendered HTML body to the client's browser. Second, after the client javascript application loads, the pointers of the pre-rendered DOM are copied into the virtual DOM, and the application proceeds as normal. All subsequent page navigation is handled locally by the client, avoiding full-page postbacks as necessary.  The `miso` function is used to perform the pointer-copying behavior client-side. @@ -525,7 +531,7 @@  ## Benchmarks -[According to benchmarks](https://medium.com/@saurabhnanda/benchmarks-fp-languages-libraries-for-front-end-development-a11af0542f7e), `miso` is among the fastest functional programming web frameworks, second only to [Elm](http://elm-lang.org).+[According to benchmarks](https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html), `miso` is among the fastest functional programming web frameworks, second only to [Elm](http://elm-lang.org).  <img src="https://cdn-images-1.medium.com/max/1600/1*6EjJTf1mhlTxd4QWsygCwA.png" width="500" height="600" /> 
ghcjs-src/Miso/FFI.hs view
@@ -27,6 +27,7 @@    , clearBody    , objectToJSON    , getWindow+   , set    ) where  import           Control.Monad@@ -46,6 +47,10 @@ import           JavaScript.Array.Internal import qualified JavaScript.Object.Internal as OI import           Unsafe.Coerce++-- | Set property on object+set :: ToJSVal v => JSString -> v -> OI.Object -> IO ()+set k v obj = toJSVal v >>= \x -> OI.setProp k x obj  -- | Convert JSVal to Maybe `Value` jsvalToValue :: JSVal -> IO (Maybe Value)
ghcjs-src/Miso/Html/Internal.hs view
@@ -96,9 +96,6 @@ -- | Convenience class for using View class ToView v where toView :: v -> View m -set :: ToJSVal v => JSString -> v -> Object -> IO ()-set k v obj = toJSVal v >>= \x -> setProp k x obj- -- | `ToJSVal` instance for `Decoder` instance ToJSVal DecodeTarget where   toJSVal (DecodeTarget xs) = toJSVal xs
ghcjs-src/Miso/Subscription/Keyboard.hs view
@@ -45,7 +45,7 @@ -- | Helper function to convert keys currently pressed to `Arrow`, given a -- mapping for keys representing up, down, left and right respectively. toArrows :: ([Int], [Int], [Int], [Int]) -> Set Int -> Arrows-toArrows (up, down, left, right) set =+toArrows (up, down, left, right) set' =   Arrows {     arrowX =       case (check left, check right) of@@ -59,7 +59,7 @@         (_,_) -> 0   }   where-    check = any (`S.member` set)+    check = any (`S.member` set')  -- | Maps `Arrows` onto a Keyboard subscription arrowsSub :: (Arrows -> action) -> Sub action
ghcjs-src/Miso/Subscription/WebSocket.hs view
@@ -52,6 +52,7 @@   | WebSocketClose CloseCode WasClean Reason   | WebSocketOpen   | WebSocketError MisoString+    deriving (Show, Eq)  websocket :: IORef (Maybe Socket) {-# NOINLINE websocket #-}
miso.cabal view
@@ -1,5 +1,5 @@ name:                miso-version:             0.18.0.0+version:             0.19.0.0 category:            Web, Miso, Data Structures license:             BSD3 license-file:        LICENSE@@ -27,12 +27,6 @@   description:     Builds Miso's examples -flag tests-  default:-    False-  description:-    Builds Miso's tests- executable todo-mvc   main-is:     Main.hs@@ -215,7 +209,7 @@ executable tests   main-is:     Main.hs-  if !impl(ghcjs) || !flag(tests)+  if !impl(ghcjs)     buildable: False   else     hs-source-dirs:@@ -226,8 +220,6 @@       aeson,       base < 5,       bytestring,-      hspec,-      hspec-core,       ghcjs-base,       QuickCheck,       quickcheck-instances,
src/Miso/Html/Element.hs view
@@ -476,13 +476,13 @@ i_ :: [Attribute action] -> [View action] -> View action i_ = nodeHtml "i" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b-b_ :: [Attribute actbon] -> [View actbon] -> View actbon+b_ :: [Attribute action] -> [View action] -> View action b_ = nodeHtml "b" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u-u_ :: [Attribute actuon] -> [View actuon] -> View actuon+u_ :: [Attribute action] -> [View action] -> View action u_ = nodeHtml "u" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q-q_ :: [Attribute actqon] -> [View actqon] -> View actqon+q_ :: [Attribute action] -> [View action] -> View action q_ = nodeHtml "q" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script script_ :: [Attribute action] -> [View action] -> View action
tests/Main.hs view
@@ -1,25 +1,30 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE BangPatterns             #-}+{-# LANGUAGE ScopedTypeVariables      #-} {-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings        #-}+{-# LANGUAGE NamedFieldPuns           #-} module Main where +import           Control.Exception hiding (assert) import           Control.Monad-import           Data.Aeson-import qualified Data.HashMap.Strict       as H+import           Control.Monad.IO.Class     (liftIO)+import           Control.Monad.Trans.State+import           Data.Aeson                 hiding (Result(..))+import qualified Data.HashMap.Strict        as H import           Data.Scientific-import qualified Data.Vector               as V+import qualified Data.Vector                as V import           Debug.Trace import           GHCJS.Marshal-import           Test.Hspec                (it, hspec, describe, shouldSatisfy, shouldBe, Spec)-import           Test.Hspec.Core.Runner    (hspecResult, Summary(..))+import           GHCJS.Types+import qualified JavaScript.Object.Internal as OI+import           System.IO.Unsafe import           Test.QuickCheck import           Test.QuickCheck.Instances+import           Test.QuickCheck.Monadic  import           Miso import           Miso.FFI-import           System.IO.Unsafe  instance Arbitrary Value where   arbitrary = sized sizedArbitraryValue@@ -51,17 +56,12 @@     in relDiff <= 0.00001  main :: IO ()-main = do-  Summary { summaryFailures } <- hspecResult tests-  phantomExit summaryFailures--tests :: Spec-tests = do+main = runTests $ do   storageTests   roundTripJSVal -storageTests :: Spec-storageTests = describe "Storage tests" $ do+storageTests :: TestM ()+storageTests = do   it "should write to and read from local storage" $ do     let obj = object [ "foo" .= ("bar" :: String) ]     setLocalStorage "foo" obj@@ -73,20 +73,108 @@     Right r <- getLocalStorage "foo"     r `shouldBe` obj +roundTripJSVal :: TestM () roundTripJSVal =- describe "Serialization tests" $ do   it "Should round trip JSVal" $ do-    property $ (\(x :: Value) -> do-      Just y <- jsvalToValue =<< toJSVal x-      compareValue x y `shouldBe` True)+    propTest iso_prop -phantomExit :: Int -> IO ()-phantomExit x-  | x <= 0 = phantomExitSuccess-  | otherwise = phantomExitFail+roundTrip+  :: Value+  -> IO Bool+roundTrip x = do+  Just y <- jsvalToValue =<< toJSVal x+  pure $ compareValue x y == True -foreign import javascript unsafe "phantom.exit(0);"-  phantomExitSuccess :: IO ()+iso_prop :: Value -> Property+iso_prop = monadicIO . run . roundTrip -foreign import javascript unsafe "phantom.exit(1);"-  phantomExitFail :: IO ()+propTest :: Testable prop => prop -> IO (Bool, String)+propTest prop = do+  r <- flip quickCheckWithResult prop stdArgs { chatty = False }+  pure $ case r of+    Success { output = o } -> (True, o)+    GaveUp { output = o } -> (False, o)+    Failure { output = o } -> (False, o)+    NoExpectedFailure { output = o } -> (False, o)+    InsufficientCoverage { output = o } -> (False, o)++foreign import javascript unsafe "window.global_test_results = $1;"+  writeToGlobalObject :: JSVal -> IO ()++runTests :: TestM () -> IO ()+runTests t = do+  results <- toJSVal =<< toResult <$> execStateT t []+  consoleLog results+  writeToGlobalObject results+    where+      toResult :: [Test] -> TestResult+      toResult xs = TestResult failed' passed' total' duration' xs+        where+          passed'   = length (filter result xs)+          failed'   = length (filter (not . result) xs)+          total'    = length xs+          duration' = sum (map duration xs)++instance ToJSVal TestResult where+  toJSVal t = do+    o@(OI.Object j) <- OI.create+    set "passed" (passed t) o+    set "failed" (failed t) o+    set "total" (total t) o+    set "duration" (duration' t) o+    set "tests" (tests t) o+    pure j++instance ToJSVal Test where+  toJSVal t = do+    o@(OI.Object j) <- OI.create+    set "name" (name t) o+    set "result" (result t) o+    set "message" (message t) o+    set "duration" (duration t) o+    pure j++it :: String -> IO (Bool, String) -> TestM ()+it name test = do+  (result, msg, time) <- liftIO $ (do+     ((x,msg),t) <- clock test+     pure (x,msg,t))+      `catch` (\(e :: SomeException) ->+         pure (False, show e, 0))+  modify (Test name result msg time:)++data TestResult+  = TestResult+  { failed :: Int+  , passed :: Int+  , total :: Int+  , duration' :: Double+  , tests :: [Test]+  } deriving (Show, Eq)++data Test+  = Test+  { name :: String+  , result :: Bool+  , message :: String+  , duration :: Double+  } deriving (Show, Eq)++type TestM a = StateT [Test] IO a++shouldBe :: (Show a, Eq a, Applicative f) => a -> a -> f (Bool, String)+shouldBe x y =+  pure $+    if x == y+      then (True, mempty)+      else (False, "Expecting: " ++ show y ++ " but got: " ++ show x)++infix 0 `shouldBe`++-- | Measure in seconds+clock :: IO a -> IO (a, Double)+clock action = do+  start <- now+  x <- action+  stop <- now+  pure (x, (stop - start) / 1000)