javascript-extras 0.2.0.2 → 0.3.0.0
raw patch · 7 files changed
+296/−281 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- JavaScript.Extras.Recast: class FromJS a
- JavaScript.Extras.Recast: class ToJS a where toJS = jsval
- JavaScript.Extras.Recast: fromJS :: FromJS a => JSVal -> IO (Maybe a)
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS (JavaScript.Array.Internal.SomeJSArray m)
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS Data.JSString.Internal.Type.JSString
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS Data.Text.Internal.Text
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Int.Int16
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Int.Int32
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Int.Int8
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Types.Bool
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Types.Char
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Types.Double
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Types.Float
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Types.Int
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Types.Word
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Word.Word16
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Word.Word32
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHC.Word.Word8
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS GHCJS.Prim.JSVal
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS JavaScript.Object.Internal.Object
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.FromJS [GHC.Types.Char]
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS (GHCJS.Foreign.Callback.Internal.Callback a)
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS (GHCJS.Foreign.Export.Export a)
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS (GHCJS.Nullable.Nullable a)
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS (JavaScript.Array.Internal.SomeJSArray m)
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS Data.JSString.Internal.Type.JSString
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS Data.Text.Internal.Text
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Int.Int16
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Int.Int32
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Int.Int8
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Types.Bool
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Types.Char
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Types.Double
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Types.Float
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Types.Int
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Types.Word
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Word.Word16
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Word.Word32
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHC.Word.Word8
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS GHCJS.Prim.JSVal
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS JavaScript.Object.Internal.Object
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS [GHC.Types.Char]
- JavaScript.Extras.Recast: instance JavaScript.Extras.Recast.ToJS a => JavaScript.Extras.Recast.ToJS (GHC.Base.Maybe a)
- JavaScript.Extras.Recast: toJS :: (ToJS a, IsJSVal a) => a -> JSVal
- JavaScript.Extras.String: strJS :: JSString -> JSVal
- JavaScript.Extras.String: strJS' :: [Char] -> JSVal
- JavaScript.Extras.String: txtJS :: Text -> JSVal
+ JavaScript.Extras.Cast: class FromJS a
+ JavaScript.Extras.Cast: class ToJS a where toJS = jsval
+ JavaScript.Extras.Cast: fromJS :: FromJS a => JSVal -> Maybe a
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS (JavaScript.Array.Internal.SomeJSArray m)
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS Data.JSString.Internal.Type.JSString
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS Data.Text.Internal.Text
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Base.String
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Int.Int16
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Int.Int32
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Int.Int8
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Types.Bool
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Types.Char
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Types.Double
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Types.Float
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Types.Int
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Types.Word
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Word.Word16
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Word.Word32
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHC.Word.Word8
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS GHCJS.Prim.JSVal
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.FromJS JavaScript.Object.Internal.Object
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS (GHCJS.Foreign.Callback.Internal.Callback a)
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS (GHCJS.Foreign.Export.Export a)
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS (GHCJS.Nullable.Nullable a)
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS (JavaScript.Array.Internal.SomeJSArray m)
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS Data.JSString.Internal.Type.JSString
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS Data.Text.Internal.Text
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Base.String
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Int.Int16
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Int.Int32
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Int.Int8
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Types.Bool
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Types.Char
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Types.Double
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Types.Float
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Types.Int
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Types.Word
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Word.Word16
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Word.Word32
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHC.Word.Word8
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS GHCJS.Prim.JSVal
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS JavaScript.Object.Internal.Object
+ JavaScript.Extras.Cast: instance JavaScript.Extras.Cast.ToJS a => JavaScript.Extras.Cast.ToJS (GHC.Base.Maybe a)
+ JavaScript.Extras.Cast: toJS :: (ToJS a, IsJSVal a) => a -> JSVal
+ 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 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: newtype JSVar
+ JavaScript.Extras.JSVar: toJS' :: ToJS a => a -> JSVar
- JavaScript.Extras.Property: getProperty :: JSString -> JSVal -> IO JSVal
+ JavaScript.Extras.Property: getProperty :: JSString -> JSVal -> IO JSVar
- JavaScript.Extras.Property: type Property = (JSString, JSVal)
+ JavaScript.Extras.Property: type Property = (JSString, JSVar)
Files
- javascript-extras.cabal +3/−3
- src/JavaScript/Extras.hs +5/−5
- src/JavaScript/Extras/Cast.hs +243/−0
- src/JavaScript/Extras/JSVar.hs +35/−0
- src/JavaScript/Extras/Property.hs +10/−9
- src/JavaScript/Extras/Recast.hs +0/−244
- src/JavaScript/Extras/String.hs +0/−20
javascript-extras.cabal view
@@ -1,5 +1,5 @@ name: javascript-extras-version: 0.2.0.2+version: 0.3.0.0 synopsis: Extra javascript functions when using GHCJS description: Extra javascript functions when using GHCJS homepage: https://github.com/louispan/javascript-extras#readme@@ -17,10 +17,10 @@ hs-source-dirs: src js-sources: jsbits/extras.js exposed-modules: JavaScript.Extras+ JavaScript.Extras.Cast JavaScript.Extras.Number JavaScript.Extras.Property- JavaScript.Extras.Recast- JavaScript.Extras.String+ JavaScript.Extras.JSVar build-depends: base >= 4.7 && < 5 , deepseq >= 1.4 && < 2 , parallel >= 3.2 && < 4
src/JavaScript/Extras.hs view
@@ -1,11 +1,11 @@ module JavaScript.Extras- ( module JavaScript.Extras.Number+ ( module JavaScript.Extras.Cast+ , module JavaScript.Extras.JSVar+ , module JavaScript.Extras.Number , module JavaScript.Extras.Property- , module JavaScript.Extras.Recast- , module JavaScript.Extras.String ) where +import JavaScript.Extras.Cast+import JavaScript.Extras.JSVar import JavaScript.Extras.Number import JavaScript.Extras.Property-import JavaScript.Extras.Recast-import JavaScript.Extras.String
+ src/JavaScript/Extras/Cast.hs view
@@ -0,0 +1,243 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}++module JavaScript.Extras.Cast+ ( ToJS(..)+ , FromJS(..)+ ) where++import qualified Data.JSString as JS+import qualified Data.Text as T+import GHC.Int+import GHC.Word+import qualified GHCJS.Foreign.Callback as J+import qualified GHCJS.Foreign.Export as J+import qualified GHCJS.Foreign.Internal as JFI+import qualified GHCJS.Marshal.Pure as J+import qualified GHCJS.Nullable as J+import qualified GHCJS.Types as J+import qualified JavaScript.Array.Internal as JAI+import qualified JavaScript.Object.Internal as JOI++-- | This provides a consistent way to convert to JSVal, with different semantics for Char.+-- In the Char's instance of ToJS, it converts to a string instead of integer - IMHO this is less surprising.+--+-- The other reason for this class is while GHCJS base provide both IsJSVal and PToJSVal to convert to jsval,+-- some types are instances of one or the other class.+-- This means you can't use the "Maybe a" instance of PToJSVal if it contains IsISJVal but not pToJSVal.+class ToJS a where+ -- | This is a pure conversion, so instances must be able to convert+ -- the same or equivalent JSVal each time.+ toJS :: a -> J.JSVal+ default toJS :: J.IsJSVal a => a -> J.JSVal+ toJS = J.jsval++instance ToJS J.JSVal where+ toJS = id+instance ToJS (J.Callback a)+instance ToJS (J.Export a)+instance ToJS (J.Nullable a) where+ toJS (J.Nullable a) = a+instance ToJS (JAI.SomeJSArray m)+instance ToJS JOI.Object+instance ToJS Bool where+ toJS = J.pToJSVal+-- | Char instance converts to string+instance ToJS Char where+ toJS a = J.pToJSVal [a]+instance ToJS Double where+ toJS = J.pToJSVal+instance ToJS Float where+ toJS = J.pToJSVal+instance ToJS Int where+ toJS = J.pToJSVal+instance ToJS Int8 where+ toJS = J.pToJSVal+instance ToJS Int16 where+ toJS = J.pToJSVal+instance ToJS Int32 where+ toJS = J.pToJSVal+instance ToJS Word where+ toJS = J.pToJSVal+instance ToJS Word8 where+ toJS = J.pToJSVal+instance ToJS Word16 where+ toJS = J.pToJSVal+instance ToJS Word32 where+ toJS = J.pToJSVal+instance ToJS T.Text where+ toJS = J.pToJSVal+instance ToJS String where+ toJS = J.pToJSVal+instance ToJS J.JSString+instance ToJS a => ToJS (Maybe a) where+ toJS Nothing = J.nullRef+ toJS (Just a) = toJS a++-- | This provides a consistent way to safely convert from JSVal.+-- The semantics is that if the return value is a Just, then the JSVal is not a null value.+-- Also, Nothing is also returned for values out of range. They are not silently truncated.+-- (Except for Float where there may be loss of precision) during conversion.+--+-- The reason for this class is because GHCJS.Marshal.fromJSVal and GHCJS.Marshal.pFromJSVal+-- are not safe to use as it assumes that the JSVal are of the correct type and not null.+-- (https://github.com/ghcjs/ghcjs-base/issues/87).+-- The safe way to convert from JSVal is to use JavaScript.Cast or to use the 'Maybe a' instance of FromJSVal,+-- ie @fromJSVal :: JSVal -> IO (Maybe (Maybe a))@, which is a bit more awkward to use, and requires IO.+-- Also, Javascript.Cast doesn't have much instances, and it hardcodes the instance detection method+-- to javascript `isinstance` which is not sufficient for complex types (https://github.com/ghcjs/ghcjs-base/issues/86).+--+-- It is actually safe to convert from JSVal without IO because every JSVal is a copy of a value or reference.+-- The copy never change, so the conversion will always convert to the same result/object every time.+class FromJS a where+ fromJS :: J.JSVal -> Maybe a++instance FromJS J.JSVal where+ fromJS a | J.isUndefined a || J.isNull a = Nothing+ fromJS a = Just a++instance FromJS (JAI.SomeJSArray m) where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONArray = Just $ JAI.SomeJSArray a+ fromJS _ = Nothing++instance FromJS JOI.Object where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONObject = Just $ JOI.Object a+ fromJS _ = Nothing++instance FromJS Bool where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONBool = J.pFromJSVal a+ fromJS _ = Nothing++-- | This will only succeed on a single character string+instance FromJS Char where+ fromJS a =+ case JFI.jsonTypeOf a of+ JFI.JSONString ->+ let a' = J.pFromJSVal a -- convert to JSString+ mb = JS.uncons a'+ in case mb of+ Nothing -> Nothing+ Just (h, t) ->+ if JS.null t+ then Just h+ else Nothing+ _ -> Nothing++instance FromJS Double where+ fromJS a = let t = JFI.jsonTypeOf a+ in if t == JFI.JSONInteger || t == JFI.JSONFloat+ then J.pFromJSVal a+ else Nothing++instance FromJS Float where+ fromJS a = let t = JFI.jsonTypeOf a+ in if t == JFI.JSONInteger || t == JFI.JSONFloat+ then J.pFromJSVal a+ else Nothing++instance FromJS Int where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinIntBounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Int8 where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinInt8Bounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Int16 where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinInt16Bounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Int32 where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinInt32Bounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Word where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWordBounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Word8 where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWord8Bounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Word16 where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWord16Bounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS Word32 where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWord32Bounds a minBound maxBound = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS T.Text where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONString = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS String where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONString = J.pFromJSVal a+ fromJS _ = Nothing++instance FromJS J.JSString where+ fromJS a | JFI.jsonTypeOf a == JFI.JSONString = J.pFromJSVal a+ fromJS _ = Nothing++#ifdef __GHCJS__++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinIntBounds :: J.JSVal -> Int -> Int -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinInt8Bounds :: J.JSVal -> Int8 -> Int8 -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinInt16Bounds :: J.JSVal -> Int16 -> Int16 -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinInt32Bounds :: J.JSVal -> Int32 -> Int32 -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinWordBounds :: J.JSVal -> Word -> Word -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinWord8Bounds :: J.JSVal -> Word8 -> Word8 -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinWord16Bounds :: J.JSVal -> Word16 -> Word16 -> Bool++foreign import javascript unsafe+ "($1 >= $2) || ($1 <= $3)"+ js_withinWord32Bounds :: J.JSVal -> Word32 -> Word32 -> Bool++#else++js_withinIntBounds :: J.JSVal -> Int -> Int -> Bool+js_withinIntBounds _ _ _ = False++js_withinInt8Bounds :: J.JSVal -> Int8 -> Int8 -> Bool+js_withinInt8Bounds _ _ _ = False++js_withinInt16Bounds :: J.JSVal -> Int8 -> Int8 -> Bool+js_withinInt16Bounds _ _ _ = False++js_withinInt32Bounds :: J.JSVal -> Int8 -> Int8 -> Bool+js_withinInt32Bounds _ _ _ = False++js_withinWordBounds :: J.JSVal -> Word -> Word -> Bool+js_withinWordBounds _ _ _ = False++js_withinWord8Bounds :: J.JSVal -> Word8 -> Word8 -> Bool+js_withinWord8Bounds _ _ _ = False++js_withinWord16Bounds :: J.JSVal -> Word16 -> Word16 -> Bool+js_withinWord16Bounds _ _ _ = False++js_withinWord32Bounds :: J.JSVal -> Word32 -> Word32 -> Bool+js_withinWord32Bounds _ _ _ = False++#endif
+ src/JavaScript/Extras/JSVar.hs view
@@ -0,0 +1,35 @@+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 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
src/JavaScript/Extras/Property.hs view
@@ -16,16 +16,17 @@ import qualified GHCJS.Types as J 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, J.JSVal)+type Property = (J.JSString, JE.JSVar) -- | get a property of any JSVal. If a null or undefined is queried, the result will also be null-getProperty :: J.JSString -> J.JSVal -> IO J.JSVal+getProperty :: J.JSString -> J.JSVal -> IO JE.JSVar getProperty k x = let k' = J.pToJSVal k in if J.isUndefined x || J.isNull x || J.isUndefined k' || J.isNull k'- then pure J.nullRef+ then pure $ JE.JSVar J.nullRef else js_unsafeGetProperty k x -- | set a property of any JSVal@@ -45,19 +46,19 @@ toProperties :: JO.Object -> IO [Property] toProperties obj = do props <- JO.listProps obj- traverse (\k -> (\v -> (k, v)) <$> JO.unsafeGetProp k obj) props+ traverse (\k -> (\v -> (k, JE.JSVar 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 J.JSVal+ js_unsafeGetProperty :: J.JSString -> J.JSVal -> IO JE.JSVar -- | throws an exception if undefined or null foreign import javascript unsafe "$3[$1] = $2;"- js_unsafeSetProperty :: J.JSString -> J.JSVal -> J.JSVal -> IO ()+ js_unsafeSetProperty :: J.JSString -> JE.JSVar -> J.JSVal -> 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@@ -67,11 +68,11 @@ #else -- | throws an exception if undefined or null-js_unsafeGetProperty :: J.JSString -> J.JSVal -> IO J.JSVal-js_unsafeGetProperty _ _ = pure J.nullRef+js_unsafeGetProperty :: J.JSString -> J.JSVal -> IO JE.JSVar+js_unsafeGetProperty _ _ = pure $ JE.JSVar J.nullRef -- | throws an exception if undefined or null-js_unsafeSetProperty :: J.JSString -> J.JSVal -> J.JSVal -> IO ()+js_unsafeSetProperty :: J.JSString -> JE.JSVar -> J.JSVal -> IO () js_unsafeSetProperty _ _ _ = pure () -- | zip list of string and JSVal to object, lists must have been completely forced first
− src/JavaScript/Extras/Recast.hs
@@ -1,244 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE FlexibleInstances #-}--module JavaScript.Extras.Recast- ( ToJS(..)- , FromJS(..)- ) where--import qualified Data.JSString as JS-import qualified Data.Text as T-import GHC.Int-import GHC.Word-import qualified GHCJS.Foreign.Callback as J-import qualified GHCJS.Foreign.Export as J-import qualified GHCJS.Foreign.Internal as JFI-import qualified GHCJS.Marshal as J-import qualified GHCJS.Marshal.Pure as J-import qualified GHCJS.Nullable as J-import qualified GHCJS.Types as J-import qualified JavaScript.Array.Internal as JAI-import qualified JavaScript.Object.Internal as JOI---- | This provides a consistent way to convert to JSVal, with different semantics for Char.--- In the Char's instance of ToJS, it converts to a string instead of integer - IMHO this is less surprising.------ The other reason for this class is while GHCJS base provide both IsJSVal and PToJSVal to convert to jsval,--- some types are instances of one or the other class.--- This means you can't use the "Maybe a" instance of PToJSVal if it contains IsISJVal but not pToJSVal.-class ToJS a where- -- | This is a pure conversion, so instances must be able to convert- -- the same or equivalent JSVal each time.- toJS :: a -> J.JSVal- default toJS :: J.IsJSVal a => a -> J.JSVal- toJS = J.jsval--instance ToJS J.JSVal where- toJS = id-instance ToJS (J.Callback a)-instance ToJS (J.Export a)-instance ToJS (J.Nullable a) where- toJS (J.Nullable a) = a-instance ToJS (JAI.SomeJSArray m)-instance ToJS JOI.Object-instance ToJS Bool where- toJS = J.pToJSVal--- | Char instance converts to string-instance ToJS Char where- toJS a = J.pToJSVal [a]-instance ToJS Double where- toJS = J.pToJSVal-instance ToJS Float where- toJS = J.pToJSVal-instance ToJS Int where- toJS = J.pToJSVal-instance ToJS Int8 where- toJS = J.pToJSVal-instance ToJS Int16 where- toJS = J.pToJSVal-instance ToJS Int32 where- toJS = J.pToJSVal-instance ToJS Word where- toJS = J.pToJSVal-instance ToJS Word8 where- toJS = J.pToJSVal-instance ToJS Word16 where- toJS = J.pToJSVal-instance ToJS Word32 where- toJS = J.pToJSVal-instance ToJS T.Text where- toJS = J.pToJSVal-instance ToJS [Char] where- toJS = J.pToJSVal-instance ToJS J.JSString-instance ToJS a => ToJS (Maybe a) where- toJS Nothing = J.nullRef- toJS (Just a) = toJS a---- | This provides a consistent way to safely convert from JSVal.--- The semantics is that if the return value is a Just, then the JSVal is not a null value.--- Also, Nothing is also returned for values out of range. They are not silently truncated.--- (Except for Float where there may be loss of precision) during conversion.------ The reason for this class is because GHCJS.Marshal.fromJSVal and GHCJS.Marshal.pFromJSVal--- are not safe to use as it assumes that the JSVal are of the correct type and not null.--- (https://github.com/ghcjs/ghcjs-base/issues/87).--- The safe way to convert from JSVal is to use JavaScript.Cast or to use the 'Maybe a' instance of FromJSVal,--- ie @fromJSVal :: JSVal -> IO (Maybe (Maybe a))@, which is a bit more awkward to use.--- Also, Javascript.Cast doesn't have much instances, and it hardcodes the instance detection method--- to javascript `isinstance` which is not sufficient for complex--- types (https://github.com/ghcjs/ghcjs-base/issues/86).-class FromJS a where- -- | This is an IO because since JSVal is mutable, this function may different results- -- for the same JSVal at later points in time.- fromJS :: J.JSVal -> IO (Maybe a)--instance FromJS J.JSVal where- fromJS a | J.isUndefined a || J.isNull a = pure Nothing- fromJS a = pure $ Just a--instance FromJS (JAI.SomeJSArray m) where- fromJS a | JFI.jsonTypeOf a == JFI.JSONArray = pure . Just $ JAI.SomeJSArray a- fromJS _ = pure Nothing--instance FromJS JOI.Object where- fromJS a | JFI.jsonTypeOf a == JFI.JSONObject = pure . Just $ JOI.Object a- fromJS _ = pure Nothing--instance FromJS Bool where- fromJS a | JFI.jsonTypeOf a == JFI.JSONBool = J.fromJSVal a- fromJS _ = pure Nothing---- | This will only succeed on a single character string-instance FromJS Char where- fromJS a =- case JFI.jsonTypeOf a of- JFI.JSONString ->- let a' = J.pFromJSVal a -- convert to JSString- mb = JS.uncons a'- in case mb of- Nothing -> pure Nothing- Just (h, t) ->- if JS.null t- then pure $ Just h- else pure Nothing- _ -> pure Nothing--instance FromJS Double where- fromJS a = let t = JFI.jsonTypeOf a- in if t == JFI.JSONInteger || t == JFI.JSONFloat- then J.fromJSVal a- else pure Nothing--instance FromJS Float where- fromJS a = let t = JFI.jsonTypeOf a- in if t == JFI.JSONInteger || t == JFI.JSONFloat- then J.fromJSVal a- else pure Nothing--instance FromJS Int where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinIntBounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Int8 where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinInt8Bounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Int16 where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinInt16Bounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Int32 where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinInt32Bounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Word where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWordBounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Word8 where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWord8Bounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Word16 where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWord16Bounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS Word32 where- fromJS a | JFI.jsonTypeOf a == JFI.JSONInteger && js_withinWord32Bounds a minBound maxBound = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS T.Text where- fromJS a | JFI.jsonTypeOf a == JFI.JSONString = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS [Char] where- fromJS a | JFI.jsonTypeOf a == JFI.JSONString = J.fromJSVal a- fromJS _ = pure Nothing--instance FromJS J.JSString where- fromJS a | JFI.jsonTypeOf a == JFI.JSONString = J.fromJSVal a- fromJS _ = pure Nothing--#ifdef __GHCJS__--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinIntBounds :: J.JSVal -> Int -> Int -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinInt8Bounds :: J.JSVal -> Int8 -> Int8 -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinInt16Bounds :: J.JSVal -> Int16 -> Int16 -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinInt32Bounds :: J.JSVal -> Int32 -> Int32 -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinWordBounds :: J.JSVal -> Word -> Word -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinWord8Bounds :: J.JSVal -> Word8 -> Word8 -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinWord16Bounds :: J.JSVal -> Word16 -> Word16 -> Bool--foreign import javascript unsafe- "($1 >= $2) || ($1 <= $3)"- js_withinWord32Bounds :: J.JSVal -> Word32 -> Word32 -> Bool--#else--js_withinIntBounds :: J.JSVal -> Int -> Int -> Bool-js_withinIntBounds _ _ _ = False--js_withinInt8Bounds :: J.JSVal -> Int8 -> Int8 -> Bool-js_withinInt8Bounds _ _ _ = False--js_withinInt16Bounds :: J.JSVal -> Int8 -> Int8 -> Bool-js_withinInt16Bounds _ _ _ = False--js_withinInt32Bounds :: J.JSVal -> Int8 -> Int8 -> Bool-js_withinInt32Bounds _ _ _ = False--js_withinWordBounds :: J.JSVal -> Word -> Word -> Bool-js_withinWordBounds _ _ _ = False--js_withinWord8Bounds :: J.JSVal -> Word8 -> Word8 -> Bool-js_withinWord8Bounds _ _ _ = False--js_withinWord16Bounds :: J.JSVal -> Word16 -> Word16 -> Bool-js_withinWord16Bounds _ _ _ = False--js_withinWord32Bounds :: J.JSVal -> Word32 -> Word32 -> Bool-js_withinWord32Bounds _ _ _ = False--#endif
− src/JavaScript/Extras/String.hs
@@ -1,20 +0,0 @@-module JavaScript.Extras.String where--import JavaScript.Extras.Recast as JE-import Data.Text as T-import qualified GHCJS.Types as J---- | This makes it easier to use OverloadedStrings with inputs that accept a JSVal that could be a JSString--- Less verbose version of'toJS @JSString'-strJS :: J.JSString -> J.JSVal-strJS = JE.toJS---- | This makes it easier to use OverloadedStrings with inputs that accept a JSVal that could be a Data.Text--- Less verbose version of'toJS @Text'-txtJS :: T.Text -> J.JSVal-txtJS = JE.toJS---- | This makes it easier to use OverloadedStrings with inputs that accept a JSVal that could be a [String]--- Less verbose version of'toJS @Jtring'-strJS' :: [Char] -> J.JSVal-strJS' = JE.toJS