packages feed

javascript-extras 0.3.2.0 → 0.4.0.0

raw patch · 11 files changed

+207/−162 lines, 11 filesdep ~deepseqdep ~ghcjs-base-stubdep ~ghcjs-primPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: deepseq, ghcjs-base-stub, ghcjs-prim, parallel, text

API changes (from Hackage documentation)

- JavaScript.Extras.JSVar: JSVar :: JSVal -> JSVar
- JavaScript.Extras.JSVar: fromJS' :: FromJS a => JSVar -> Maybe a
- JavaScript.Extras.JSVar: instance Control.DeepSeq.NFData JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: instance Data.String.IsString JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: instance GHC.Show.Show JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: instance GHCJS.Internal.Types.IsJSVal JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: instance GHCJS.Marshal.Internal.PToJSVal JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: instance JavaScript.Extras.Cast.FromJS JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: instance JavaScript.Extras.Cast.ToJS JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar: js_stringify :: JSVar -> JSString
- JavaScript.Extras.JSVar: newtype JSVar
- JavaScript.Extras.JSVar: toJS' :: ToJS a => a -> JSVar
- JavaScript.Extras.JSVar.Unsafe: instance GHC.Read.Read JavaScript.Extras.JSVar.JSVar
- JavaScript.Extras.JSVar.Unsafe: js_eval :: JSString -> JSVar
+ JavaScript.Extras.JSRep: JSRep :: JSVal -> JSRep
+ JavaScript.Extras.JSRep: fromJSR :: FromJS a => JSRep -> Maybe a
+ JavaScript.Extras.JSRep: instance Control.DeepSeq.NFData JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: instance Data.String.IsString JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: instance GHC.Show.Show JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: instance GHCJS.Internal.Types.IsJSVal JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: instance GHCJS.Marshal.Internal.PToJSVal JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: instance JavaScript.Extras.Cast.FromJS JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: instance JavaScript.Extras.Cast.ToJS JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep: js_stringify :: JSRep -> JSString
+ JavaScript.Extras.JSRep: newtype JSRep
+ JavaScript.Extras.JSRep: toJSR :: ToJS a => a -> JSRep
+ JavaScript.Extras.JSRep.Unsafe: instance GHC.Read.Read JavaScript.Extras.JSRep.JSRep
+ JavaScript.Extras.JSRep.Unsafe: js_eval :: JSString -> JSRep
+ JavaScript.Extras.Number: minSafeInteger :: Int
+ JavaScript.Extras.Number: safeDecrement :: Int -> Int
+ JavaScript.Extras.Number: safeIncrement :: Int -> Int
+ JavaScript.Extras.Property: classNames :: [(JSString, Bool)] -> JSRep
- JavaScript.Extras.Cast: class ToJS a where toJS = jsval
+ JavaScript.Extras.Cast: class ToJS a
- JavaScript.Extras.Property: getProperty :: Coercible a JSVal => JSString -> a -> IO JSVar
+ JavaScript.Extras.Property: getProperty :: ToJS a => a -> JSString -> IO JSRep
- JavaScript.Extras.Property: setProperty :: Coercible a JSVal => Property -> a -> IO ()
+ JavaScript.Extras.Property: setProperty :: ToJS a => a -> Property -> IO ()
- JavaScript.Extras.Property: type Property = (JSString, JSVar)
+ JavaScript.Extras.Property: type Property = (JSString, JSRep)

Files

README.md view
@@ -1,3 +1,18 @@ [![Hackage](https://img.shields.io/hackage/v/javascript-extras.svg)](https://hackage.haskell.org/package/javascript-extras)  Extra javascript functions when using GHCJS++# Changelog++* 0.4.0.0+  - Renamed `JSVar` to `JSRep` to avoid confusion with `JSVal`+  - Renamed `toJS'` to `toJSR`+  - Renamed `fromJS'` to `fromJSR`+  - `getProperty` and `setProperty` uses `JE.ToJS a` instead of `Coercible a J.JSVal`+  - flipped the args of `getProperty` and `setProperty`+  - Moved `justSnds` to esoteric-extras `Data.Maybe.Esoteric.keepMaybes`+  - Renamed `safeModularIncrement` to `safeIncrement`+  - Renamed `safeModularDecrement` to `safeDecrement`++* 0.3.3.0+  - Added `classNames`, `justSnds`
javascript-extras.cabal view
@@ -1,5 +1,5 @@ name:                javascript-extras-version:             0.3.2.0+version:             0.4.0.0 synopsis:            Extra javascript functions when using GHCJS description:         Extra javascript functions when using GHCJS homepage:            https://github.com/louispan/javascript-extras#readme@@ -20,21 +20,21 @@                        JavaScript.Extras.Cast                        JavaScript.Extras.Number                        JavaScript.Extras.Property-                       JavaScript.Extras.JSVar-                       JavaScript.Extras.JSVar.Unsafe+                       JavaScript.Extras.JSRep+                       JavaScript.Extras.JSRep.Unsafe   build-depends:       base >= 4.7 && < 5-                     , deepseq >= 1.4 && < 2-                     , parallel >= 3.2 && < 4-                     , text >= 1.2 && < 1.3+                     , deepseq >= 1.4+                     , parallel >= 3.2+                     , text >= 1.2   default-language:    Haskell2010   ghc-options:         -Wall   if impl(ghcjs)     build-depends: ghcjs-base   if !impl(ghcjs)-    build-depends: ghcjs-base-stub >= 0.1.0.1 && < 1+    build-depends: ghcjs-base-stub >= 0.1.0.1  executable javascript-extras-test-  hs-source-dirs:      test/haskell+  hs-source-dirs:      test/hs   main-is:             Main.hs   ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N   cpp-options:         -DGHCJS_BROWSER@@ -44,9 +44,9 @@   default-extensions:  ApplicativeDo   if impl(ghcjs)     build-depends: ghcjs-base-                 , ghcjs-prim >= 0.1 && < 0.2+                 , ghcjs-prim >= 0.1   if !impl(ghcjs)-    build-depends: ghcjs-base-stub >= 0.1.0.2 && < 1+    build-depends: ghcjs-base-stub >= 0.1.0.2  source-repository head   type:     git
src/JavaScript/Extras.hs view
@@ -1,11 +1,11 @@ module JavaScript.Extras     ( module JavaScript.Extras.Cast-    , module JavaScript.Extras.JSVar+    , module JavaScript.Extras.JSRep     , module JavaScript.Extras.Number     , module JavaScript.Extras.Property     ) where  import JavaScript.Extras.Cast-import JavaScript.Extras.JSVar+import JavaScript.Extras.JSRep import JavaScript.Extras.Number import JavaScript.Extras.Property
+ src/JavaScript/Extras/JSRep.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE CPP #-}++module JavaScript.Extras.JSRep where++import Control.DeepSeq+import Data.Coerce+import Data.JSString as JS+import Data.String+import qualified GHCJS.Marshal.Pure as J+import qualified GHCJS.Types as J+import JavaScript.Extras.Cast as JE++-- | Wrapper to have a JSVal that also have an IString instance+-- This is helpful when using OverloadedStrings+newtype JSRep = JSRep J.JSVal++instance Show JSRep where+    show = JS.unpack . js_stringify++instance J.IsJSVal JSRep++instance J.PToJSVal JSRep where+    pToJSVal = J.jsval++instance JE.ToJS JSRep++instance JE.FromJS JSRep where+    fromJS v = coerce (fromJS v :: Maybe J.JSVal)++instance IsString JSRep where+    fromString = JSRep . J.jsval . JS.pack++instance NFData JSRep where+    rnf (JSRep v) = rnf v++toJSR :: JE.ToJS a => a -> JSRep+toJSR = JSRep . toJS++fromJSR :: JE.FromJS a => JSRep -> Maybe a+fromJSR (JSRep v) = fromJS v++#ifdef __GHCJS__++foreign import javascript unsafe+  "$r = hje$stringify($1);"+  js_stringify :: JSRep -> J.JSString++#else++js_stringify :: JSRep -> J.JSString+js_stringify _ = JS.empty++#endif
+ src/JavaScript/Extras/JSRep/Unsafe.hs view
@@ -0,0 +1,26 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}++module JavaScript.Extras.JSRep.Unsafe where++import Data.JSString as JS+import qualified GHCJS.Types as J+import JavaScript.Extras.JSRep as JE++-- | Injection attack! Use with care+instance Read JE.JSRep where+    readsPrec _ str = [(js_eval (JS.pack str), [])]++#ifdef __GHCJS__++-- | Injection attack! Use with care+foreign import javascript unsafe+  "$r = hje$unstringify($1);"+  js_eval :: J.JSString -> JSRep++#else++js_eval :: J.JSString -> JSRep+js_eval _ = JSRep J.nullRef++#endif
− src/JavaScript/Extras/JSVar.hs
@@ -1,53 +0,0 @@-{-# LANGUAGE CPP #-}--module JavaScript.Extras.JSVar where--import Control.DeepSeq-import Data.Coerce-import Data.JSString as JS-import Data.String-import qualified GHCJS.Marshal.Pure as J-import qualified GHCJS.Types as J-import JavaScript.Extras.Cast as JE---- | Wrapper to have a JSVal that also have an IString instance--- This is helpful when using OverloadedStrings-newtype JSVar = JSVar J.JSVal--instance Show JSVar where-    show = JS.unpack . js_stringify--instance J.IsJSVal JSVar--instance J.PToJSVal JSVar where-    pToJSVal = J.jsval--instance JE.ToJS JSVar--instance JE.FromJS JSVar where-    fromJS v = coerce (fromJS v :: Maybe J.JSVal)--instance IsString JSVar where-    fromString = JSVar . J.jsval . JS.pack--instance NFData JSVar where-    rnf (JSVar v) = rnf v--toJS' :: JE.ToJS a => a -> JSVar-toJS' = JSVar . toJS--fromJS' :: JE.FromJS a => JSVar -> Maybe a-fromJS' (JSVar v) = fromJS v--#ifdef __GHCJS__--foreign import javascript unsafe-  "$r = hje$stringify($1);"-  js_stringify :: JSVar -> J.JSString--#else--js_stringify :: JSVar -> J.JSString-js_stringify _ = JS.empty--#endif
− src/JavaScript/Extras/JSVar/Unsafe.hs
@@ -1,26 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE CPP #-}--module JavaScript.Extras.JSVar.Unsafe where--import Data.JSString as JS-import qualified GHCJS.Types as J-import JavaScript.Extras.JSVar as JE---- | Injection attack! Use with care-instance Read JE.JSVar where-    readsPrec _ str = [(js_eval (JS.pack str), [])]--#ifdef __GHCJS__---- | Injection attack! Use with care-foreign import javascript unsafe-  "$r = hje$unstringify($1);"-  js_eval :: J.JSString -> JSVar--#else--js_eval :: J.JSString -> JSVar-js_eval _ = JSVar J.nullRef--#endif
src/JavaScript/Extras/Number.hs view
@@ -2,20 +2,41 @@  module JavaScript.Extras.Number     ( maxSafeInteger+    , minSafeInteger+    , safeIncrement+    , safeDecrement     ) where  maxSafeInteger :: Int maxSafeInteger = js_maxSafeInteger +minSafeInteger :: Int+minSafeInteger = js_minSafeInteger++-- | always returns a number between [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]+safeIncrement :: Int -> Int+safeIncrement i = if i >= maxSafeInteger then minSafeInteger else i + 1++-- | always returns a number between [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER]+safeDecrement :: Int -> Int+safeDecrement i = if i <= minSafeInteger then maxSafeInteger else i - 1+ #ifdef __GHCJS__  foreign import javascript unsafe   "Number.MAX_SAFE_INTEGER"   js_maxSafeInteger :: Int +foreign import javascript unsafe+  "Number.MIN_SAFE_INTEGER"+  js_minSafeInteger :: Int+ #else  js_maxSafeInteger :: Int js_maxSafeInteger = 0++js_minSafeInteger :: Int+js_minSafeInteger = 0  #endif
src/JavaScript/Extras/Property.hs view
@@ -1,9 +1,11 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GHCForeignImportPrim #-}+{-# LANGUAGE TupleSections #-}  module JavaScript.Extras.Property-    ( Property+    ( classNames+    , Property     , getProperty     , setProperty     , fromProperties@@ -12,71 +14,78 @@  import Control.DeepSeq import Control.Parallel-import Data.Coerce+import qualified Data.JSString as JS import qualified GHC.Exts as Exts import qualified GHCJS.Marshal.Pure as J import qualified GHCJS.Types as J+import qualified JavaScript.Extras.Cast as JE+import qualified JavaScript.Extras.JSRep as JE import qualified JavaScript.Object as JO import qualified JavaScript.Object.Internal as JOI-import qualified JavaScript.Extras.JSVar as JE import Unsafe.Coerce -type Property = (J.JSString, JE.JSVar)+type Property = (J.JSString, JE.JSRep) +-- | Creates a JE.JSRep single string for "className" property from a list of (JSString, Bool)+-- Idea from https://github.com/JedWatson/classnames+classNames :: [(J.JSString, Bool)] -> JE.JSRep+classNames = JE.toJSR . JS.unwords . fmap fst . filter snd+ -- | get a property of any JSVal. If a null or undefined is queried, the result will also be null-getProperty :: Coercible a J.JSVal => J.JSString -> a -> IO JE.JSVar-getProperty k a = let k' = J.pToJSVal k-                      x = coerce a+getProperty :: JE.ToJS a => a -> J.JSString -> IO JE.JSRep+getProperty a k = let k' = J.pToJSVal k+                      x = JE.toJS a                   in if J.isUndefined x || J.isNull x                          || J.isUndefined k' || J.isNull k'-                     then pure $ JE.JSVar J.nullRef-                     else js_unsafeGetProperty k x+                     then pure $ JE.JSRep J.nullRef+                     else js_unsafeGetProperty x k  -- | set a property of any JSVal-setProperty :: Coercible a J.JSVal => Property -> a -> IO ()-setProperty (k, v) a = let k' = J.pToJSVal k-                           x = coerce a+setProperty :: JE.ToJS a => a -> Property -> IO ()+setProperty a (k, v) = let k' = J.pToJSVal k+                           x = JE.toJS a                     in if J.isUndefined x || J.isNull x                           || J.isUndefined k' || J.isNull k'                        then pure ()-                       else js_unsafeSetProperty k v x+                       else js_unsafeSetProperty x k v  fromProperties :: [Property] -> JO.Object fromProperties xs =-    let (names, props) = unzip xs-    in (rnf names `seq` rnf props) `pseq` js_toJSObjectPure (unsafeCoerce names) (unsafeCoerce props)+    let (names, values) = unzip xs+    in (rnf names `seq` rnf values) `pseq` js_toJSObjectPure (unsafeCoerce names) (unsafeCoerce values)   toProperties :: JO.Object -> IO [Property] toProperties obj = do    props <- JO.listProps obj-   traverse (\k -> (\v -> (k, JE.JSVar v)) <$> JO.unsafeGetProp k obj) props+   traverse (\k -> (\v -> (k, JE.JSRep v)) <$> JO.unsafeGetProp k obj) props  #ifdef __GHCJS__  -- | throws an exception if undefined or null foreign import javascript unsafe-  "$2[$1]"-  js_unsafeGetProperty :: J.JSString -> J.JSVal -> IO JE.JSVar+  "$1[$2]"+  js_unsafeGetProperty :: J.JSVal -> J.JSString -> IO JE.JSRep  -- | throws an exception if undefined or null foreign import javascript unsafe-  "$3[$1] = $2;"-  js_unsafeSetProperty :: J.JSString -> JE.JSVar -> J.JSVal -> IO ()+  "$1[$2] = $3;"+  js_unsafeSetProperty :: J.JSVal -> J.JSString -> JE.JSRep -> IO ()  -- | zip list of string and JSVal to object, lists must have been completely forced first -- Using the idea from JavaScript.Array.Internal.fromList h$fromHsListJSVal-foreign import javascript unsafe "hje$fromHsZipListJSVal($1, $2)"+foreign import javascript unsafe+  "hje$fromHsZipListJSVal($1, $2)"   js_toJSObjectPure :: Exts.Any -> Exts.Any -> JO.Object  #else  -- | throws an exception if undefined or null-js_unsafeGetProperty :: J.JSString -> J.JSVal -> IO JE.JSVar-js_unsafeGetProperty _ _ = pure $ JE.JSVar J.nullRef+js_unsafeGetProperty :: J.JSVal -> J.JSString -> IO JE.JSRep+js_unsafeGetProperty _ _ = pure $ JE.JSRep J.nullRef  -- | throws an exception if undefined or null-js_unsafeSetProperty :: J.JSString -> JE.JSVar -> J.JSVal -> IO ()+js_unsafeSetProperty :: J.JSVal -> J.JSString -> JE.JSRep -> IO () js_unsafeSetProperty _ _ _ = pure ()  -- | zip list of string and JSVal to object, lists must have been completely forced first
− test/haskell/Main.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--module Main (main) where--import qualified Data.JSString as JS-import qualified GHCJS.Foreign.Callback as J-import qualified GHCJS.Types as J-import qualified JavaScript.Extras as JE-import qualified JavaScript.Extras.JSVar.Unsafe as JE--#ifdef __GHCJS__--test :: JE.JSVar -> IO ()-test x = do-    let str = show x-        x' = read str :: JE.JSVar-        str' = show x'-    js_write $ "Test: " `mappend` (JS.pack str) `mappend` " == " `mappend` (JS.pack str')--main :: IO ()-main = do-    test js_int-    test js_obj-    cb <- J.syncCallback' (pure (JE.toJS js_int))-    test (JE.JSVar (J.jsval cb))-    J.releaseCallback cb-    test (JE.JSVar (J.jsval cb))--foreign import javascript unsafe-  "document.write('<p>' + $1 + '</p>')"-  js_write :: JS.JSString -> IO ()--foreign import javascript unsafe-  "5"-  js_int :: JE.JSVar--foreign import javascript unsafe-  "{ 'hello': 'world' }"-  js_obj :: JE.JSVar--#else--main :: IO ()-main = pure ()--#endif
+ test/hs/Main.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++#ifdef __GHCJS__++import qualified Data.JSString as JS+import qualified GHCJS.Foreign.Callback as J+import qualified GHCJS.Types as J+import qualified JavaScript.Extras as JE+import JavaScript.Extras.JSRep.Unsafe ()++test :: JE.JSRep -> IO ()+test x = do+    let str = show x+        x' = read str :: JE.JSRep+        str' = show x'+    js_write $ "Test: " `mappend` (JS.pack str) `mappend` " == " `mappend` (JS.pack str')++main :: IO ()+main = do+    test js_int+    test js_obj+    cb <- J.syncCallback' (pure (JE.toJS js_int))+    test (JE.JSRep (J.jsval cb))+    J.releaseCallback cb+    test (JE.JSRep (J.jsval cb))++foreign import javascript unsafe+  "document.write('<p>' + $1 + '</p>')"+  js_write :: JS.JSString -> IO ()++foreign import javascript unsafe+  "5"+  js_int :: JE.JSRep++foreign import javascript unsafe+  "{ 'hello': 'world' }"+  js_obj :: JE.JSRep++#else++main :: IO ()+main = pure ()++#endif