Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module exposes the browser's native console logging and debugging features, including underutilized features such as time measurement, table displays, and assertions.
Synopsis
- class LogJS (c :: Type -> Constraint) where
- class Assert (c :: Type -> Constraint) where
- class LogJS c => Trapper c where
- trapper :: c a => JSContextRef -> a -> a
- askJSM :: MonadJSM m => m JSContextRef
- log :: forall c a m. MonadJSM m => LogJS c => c a => a -> m ()
- debug :: forall c a m. MonadJSM m => LogJS c => c a => a -> m ()
- info :: forall c a m. MonadJSM m => LogJS c => c a => a -> m ()
- warn :: forall c a m. MonadJSM m => LogJS c => c a => a -> m ()
- table :: MonadJSM m => ToJSON a => [a] -> m ()
- newtype TimeLabel = TimeLabel {
- unTimeLabel :: Text
- time :: MonadJSM m => TimeLabel -> m ()
- timeEnd :: MonadJSM m => TimeLabel -> m ()
- class ToJSVal a
- class ToJSON a
Classes
class LogJS (c :: Type -> Constraint) where Source #
LogJS
is the base class for logging to the browser console.
Browser consoles contain rich tooling for exploring JavaScript objects,
DOM nodes, and much more. To take advantage of these native features, we
need to choose how we are going to log. The LogJS
class is intended to
be used in conjunction with TypeApplications
.
data Person = Person { first :: String, last :: String, age :: Int } deriving (Generic, ToJSON) main = logJS @ToJSON "log" $ Person "bob" "saget" 45
is effectively equivalent to:
console.log({first: "bob", last: "saget", age: 45})
in that the console will render with nice expand/collapse object exploration features.
Instances
LogJS Show Source # | Logs against |
LogJS ToJSON Source # | Logs against |
LogJS ToJSVal Source # | Logs against |
class Assert (c :: Type -> Constraint) where Source #
Assert is a class for assertion programming. It behaves the same as LogJS
but calls
console.assert instead of
other console methods. This will only have an effect if the Bool
provided to assert
is False
.
class LogJS c => Trapper c where Source #
Trapper is a class intended for continuous logging of your application and the catching of helpless animals.
Usage is along the lines of trace
where the effect of logging is implicit.
To make this work in both GHC and GHCjs contexts, you do need to
pass the JSContextRef
in manually (askJSM
re-exported here for convenience).
main :: IO () main = runJSorWarp 8080 $ do ctx <- askJSM simple runParDiff initial (view . trapper @ToJSON ctx) getBody
Nothing
trapper :: c a => JSContextRef -> a -> a Source #
Instances
Trapper Show Source # | |
Defined in Shpadoinkle.Console trapper :: Show a => JSContextRef -> a -> a Source # | |
Trapper ToJSON Source # | |
Defined in Shpadoinkle.Console trapper :: ToJSON a => JSContextRef -> a -> a Source # | |
Trapper ToJSVal Source # | |
Defined in Shpadoinkle.Console trapper :: ToJSVal a => JSContextRef -> a -> a Source # |
askJSM :: MonadJSM m => m JSContextRef #
Gets the JavaScript context from the monad
Native methods
Log levels
log :: forall c a m. MonadJSM m => LogJS c => c a => a -> m () Source #
Log to the console using console.log
debug :: forall c a m. MonadJSM m => LogJS c => c a => a -> m () Source #
Log with the "debug" log level using console.debug
info :: forall c a m. MonadJSM m => LogJS c => c a => a -> m () Source #
Log with the "info" log level using console.info
warn :: forall c a m. MonadJSM m => LogJS c => c a => a -> m () Source #
Log with the "warn" log level using console.warn
Fancy display
table :: MonadJSM m => ToJSON a => [a] -> m () Source #
Log a list of JSON objects to the console where it will rendered as a table using console.table
Time Measurement
A unique label for a timer. This is used to tie calls to console.time to console.timeEnd
timeEnd :: MonadJSM m => TimeLabel -> m () Source #
End a timer and print the milliseconds elapsed since it started using console.timeEnd
Re-exports
Instances
ToJSVal Function | |
ToJSVal JSNull | Makes a |
ToJSVal JSValue | Makes a JavaScript value from a |
Assert ToJSVal Source # | |
Trapper ToJSVal Source # | |
Defined in Shpadoinkle.Console trapper :: ToJSVal a => JSContextRef -> a -> a Source # | |
LogJS ToJSVal Source # | Logs against |
A type that can be converted to JSON.
Instances in general must specify toJSON
and should (but don't need
to) specify toEncoding
.
An example type and instance:
-- Allow ourselves to writeText
literals. {-# LANGUAGE OverloadedStrings #-} data Coord = Coord { x :: Double, y :: Double } instanceToJSON
Coord wheretoJSON
(Coord x y) =object
["x".=
x, "y".=
y]toEncoding
(Coord x y) =pairs
("x".=
x<>
"y".=
y)
Instead of manually writing your ToJSON
instance, there are two options
to do it automatically:
- Data.Aeson.TH provides Template Haskell functions which will derive an instance at compile time. The generated instance is optimized for your type so it will probably be more efficient than the following option.
- The compiler can provide a default generic implementation for
toJSON
.
To use the second, simply add a deriving
clause to your
datatype and declare a Generic
ToJSON
instance. If you require nothing other than
defaultOptions
, it is sufficient to write (and this is the only
alternative where the default toJSON
implementation is sufficient):
{-# LANGUAGE DeriveGeneric #-} import GHC.Generics data Coord = Coord { x :: Double, y :: Double } derivingGeneric
instanceToJSON
Coord wheretoEncoding
=genericToEncoding
defaultOptions
If on the other hand you wish to customize the generic decoding, you have to implement both methods:
customOptions =defaultOptions
{fieldLabelModifier
=map
toUpper
} instanceToJSON
Coord wheretoJSON
=genericToJSON
customOptionstoEncoding
=genericToEncoding
customOptions
Previous versions of this library only had the toJSON
method. Adding
toEncoding
had two reasons:
- toEncoding is more efficient for the common case that the output of
toJSON
is directly serialized to aByteString
. Further, expressing either method in terms of the other would be non-optimal. - The choice of defaults allows a smooth transition for existing users:
Existing instances that do not define
toEncoding
still compile and have the correct semantics. This is ensured by making the default implementation oftoEncoding
usetoJSON
. This produces correct results, but since it performs an intermediate conversion to aValue
, it will be less efficient than directly emitting anEncoding
. (this also means that specifying nothing more thaninstance ToJSON Coord
would be sufficient as a generically decoding instance, but there probably exists no good reason to not specifytoEncoding
in new instances.)