inline-js-core-0.0.1.0: Call JavaScript from Haskell.
Safe HaskellNone
LanguageHaskell2010

Language.JavaScript.Inline.Core

Synopsis

Session management

data Config Source #

Constructors

Config 

Fields

  • nodePath :: FilePath

    Path to the node executable. Defaults to node.

  • nodeExtraArgs :: [String]

    Extra node arguments that appear before the eval server script's file path. These arguments won't show up in process.argv.

  • nodeExtraEnv :: [(String, String)]

    Extra environment variables to pass to node. Will shadow already existing ones.

  • nodeModules :: Maybe FilePath

    To require() or import() third-party packages, set this to the node_modules directory path.

  • nodeExportSyncBufferSize :: Int

    Size in MiBs of the buffer for passing results of functions exported by exportSync. Most users don't need to care about this. Defaults to 1.

Instances

Instances details
Show Config Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Session

data Session Source #

Instances

Instances details
Show Session Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Session

closeSession :: Session -> IO () Source #

After a Session is closed, no more messages can be sent to node. Use this to close the Session if node should still run for some time to allow previous evaluation results to be sent back. Blocks until node process exits.

killSession :: Session -> IO () Source #

Terminate the node process immediately. Use this to close the Session if node doesn't need to run any more. Blocks until node process exits.

withSession :: Config -> (Session -> IO r) -> IO r Source #

Create a Session with newSession, run the passed computation, then free the Session with killSession. The return value is forced to WHNF before freeing the Session to reduce the likelihood of use-after-free errors.

Haskell/JavaScript data marshaling

data JSExpr Source #

Represents a JavaScript expression.

Use the IsString instance to convert a String to JSExpr, and the Semigroup instance for concating JSExpr. It's also possible to embed other things into JSExpr, e.g. a buffer literal, JSON value or a JSVal.

Instances

Instances details
Show JSExpr Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Message

IsString JSExpr Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Message

Methods

fromString :: String -> JSExpr #

Semigroup JSExpr Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Message

Monoid JSExpr Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Message

data JSVal Source #

An opaque reference of a JavaScript value. Each JSVal is registered with a finalizer which frees the reference on the node side when it's garbage collected in Haskell. It's also possible to manually free a JSVal using freeJSVal.

data RawJSType Source #

To convert a JavaScript value to Haskell, we need to specify its "raw type", which can be one of the following:

Constructors

RawNone

The JavaScript value is discarded.

RawBuffer

The JavaScript value is an ArrayBufferView, ArrayBuffer or string.

RawJSON

The JavaScript value can be JSON-encoded via JSON.stringify().

RawJSVal

The JavaScript value should be managed as a JSVal.

Instances

Instances details
Show RawJSType Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Message

class ToJS a where Source #

Haskell types which can be converted to JavaScript.

Methods

toJS :: a -> JSExpr Source #

Encodes a Haskell value to JSExpr.

Instances

Instances details
ToJS () Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Class

Methods

toJS :: () -> JSExpr Source #

ToJS ByteString Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Class

ToJS JSVal Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Class

Methods

toJS :: JSVal -> JSExpr Source #

ToJS EncodedJSON Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Class

ToJS EncodedString Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Class

class FromJS a where Source #

Haskell types which can be converted from JavaScript.

Methods

rawJSType :: Proxy a -> RawJSType Source #

The JavaScript value's RawJSType.

toRawJSType :: Proxy a -> JSExpr Source #

A synchronous JavaScript function which encodes a value to its RawJSType.

fromJS :: Session -> ByteString -> IO a Source #

A Haskell function which decodes the Haskell value from the serialized RawJSType.

Performing evaluation

eval :: forall a. FromJS a => Session -> JSExpr -> IO a Source #

Evaluate a JSExpr and return the result. Evaluation is asynchronous. When this function returns, the eval request has been sent to the eval server, but the result may not be sent back yet. The returned value is a thunk, and forcing it to WHNF will block until the result is sent back.

The caveats of lazy I/O apply here as well. For instance, returning evaluation result from a with-style function may cause a use-after-free problem. In case when it's desirable to ensure the evaluation has completed at a certain point, use evaluate or BangPatterns to force the result value.

Modeling asynchronousity with laziness enables us to simplify API. Users can easily regain strictness from the lazy API; if we do it the other way around and provide strict-by-default eval functions, we'll need to explicitly decouple sending of eval requests and receiving of eval results, which complicates the API.

On the eval server side, the result value is awaited before further processing. Therefore if it's a Promise, the eval result will be the resolved value instead of the Promise itself. If the Promise value needs to be returned, wrap it in another object (e.g. a single-element array).

importCJS :: Session -> FilePath -> IO JSVal Source #

Import a CommonJS module file and return its module.exports object. The module file path can be absolute, or relative to the current Haskell process. The imported module will be retained in the require() loader cache.

importMJS :: Session -> FilePath -> IO JSVal Source #

Import an ECMAScript module file and return its module namespace object. The module file path can be absolute, or relative to the current Haskell process. The imported module will be retained in the ESM loader cache.

Importing JavaScript functions to Haskell

class Import f Source #

The class of Haskell functions which can be imported from JavaScript function JSVals. The Haskell function type should be a -> b -> .. -> IO r, where the arguments a, b, etc are ToJS instances, and the result r is FromJS instance.

Minimal complete definition

importMonomorphize

Instances

Instances details
FromJS r => Import (IO r) Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Import

Methods

importMonomorphize :: Session -> JSVal -> [JSExpr] -> IO r

(ToJS a, Import b) => Import (a -> b) Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Import

Methods

importMonomorphize :: Session -> JSVal -> [JSExpr] -> a -> b

importJSFunc :: Import f => Session -> JSVal -> f Source #

Import a JavaScript function to a Haskell function.

Exporting Haskell functions to JavaScript

class Export f Source #

The class of Haskell functions which can be exported as JavaScript functions. The Haskell function type should be a -> b -> .. -> IO r, where the arguments a, b, etc are FromJS instances, and the result r is ToJS instance.

Minimal complete definition

exportArgsFromJS, exportMonomorphize

Instances

Instances details
ToJS r => Export (IO r) Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Export

(FromJS a, Export b) => Export (a -> b) Source # 
Instance details

Defined in Language.JavaScript.Inline.Core.Export

Methods

exportArgsFromJS :: Proxy (a -> b) -> [Dict FromJS]

exportMonomorphize :: Session -> (a -> b) -> [ByteString] -> IO JSExpr

export :: Export f => Session -> f -> IO JSVal Source #

Export a Haskell function as a JavaScript async function, and return its JSVal. Some points to keep in mind:

  • The Haskell function itself can call into JavaScript again via eval, and vice versa.
  • When called in JavaScript, the Haskell function is run in a forked thread.
  • If the Haskell function throws, the JavaScript function will reject with an Error with the exception string.
  • Unlike JSVals returned by eval, JSVals returned by export are not garbage collected, since we don't know when a function is garbage collected on the node side. These JSVals need to be manually freed using freeJSVal.

exportSync :: Export f => Session -> f -> IO JSVal Source #

Export a Haskell function as a JavaScript sync function. This is quite heavyweight and in most cases, export is preferrable. exportSync can be useful in certain scenarios when a sync function is desired, e.g. converting a Haskell function to a WebAssembly import.

Unlike export, exportSync has limited reentrancy:

  • The Haskell function may calculate the return value based on the result of calling into JavaScript again, but only synchronous code is supported in this case.
  • The exported JavaScript sync function must not invoke other exported JavaScript sync functions, either directly or indirectly(Haskell calling into JavaScript again).

Manual resource management

Exceptions