Full Code of LexiFi/gen_js_api for AI

master dcdd0b1dd852 cached
114 files
352.5 KB
108.8k tokens
6 symbols
1 requests
Download .txt
Showing preview only (380K chars total). Download the full file or copy to clipboard to get everything.
Repository: LexiFi/gen_js_api
Branch: master
Commit: dcdd0b1dd852
Files: 114
Total size: 352.5 KB

Directory structure:
gitextract_fdgla5ae/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       └── workflow.yml
├── .gitignore
├── .ocp-indent
├── CHANGES.md
├── CLASSES.md
├── IMPLGEN.md
├── INSTALL_AND_USE.md
├── LICENSE
├── LOW_LEVEL_BINDING.md
├── Makefile
├── NAMING.md
├── NODE_RUNTIME_BINDINGS.md
├── PPX.md
├── README.md
├── TODO.md
├── TYPES.md
├── VALUES.md
├── dune
├── dune-project
├── examples/
│   ├── calc/
│   │   ├── calc.html
│   │   ├── calc.ml
│   │   └── dune
│   ├── misc/
│   │   ├── dune
│   │   ├── jquery.mli
│   │   ├── js_date.mli
│   │   ├── js_str.mli
│   │   ├── test_jquery.html
│   │   └── test_jquery.ml
│   └── test/
│       ├── dune
│       ├── main.html
│       ├── main.ml
│       └── test_bindings.mli
├── gen_js_api.opam
├── lib/
│   ├── dune
│   ├── ojs.ml
│   ├── ojs.mli
│   ├── ojs_exn.ml
│   ├── ojs_exn.mli
│   ├── ojs_runtime.js
│   └── ojs_runtime_stubs.c
├── node-test/
│   ├── bindings/
│   │   ├── arrays.mli
│   │   ├── buffer.mli
│   │   ├── console.mli
│   │   ├── container.ml
│   │   ├── container.mli
│   │   ├── dune
│   │   ├── errors.mli
│   │   ├── expected/
│   │   │   ├── arrays.ml
│   │   │   ├── buffer.ml
│   │   │   ├── console.ml
│   │   │   ├── errors.ml
│   │   │   ├── fs.ml
│   │   │   ├── global.ml
│   │   │   ├── imports.ml
│   │   │   ├── number.ml
│   │   │   ├── path.ml
│   │   │   ├── process.ml
│   │   │   └── promise.ml
│   │   ├── fs.mli
│   │   ├── global.mli
│   │   ├── imports.js
│   │   ├── imports.mli
│   │   ├── imports.wat
│   │   ├── number.mli
│   │   ├── path.mli
│   │   ├── process.mli
│   │   └── promise.mli
│   ├── runtime_primitives/
│   │   ├── bindings.mli
│   │   ├── dune
│   │   ├── example.ml
│   │   ├── imports.js
│   │   └── imports.wat
│   └── test1/
│       ├── dune
│       ├── recursive.js
│       ├── recursive.mli
│       └── test.ml
├── ojs.opam
├── ojs.opam.template
├── ppx-driver/
│   ├── dune
│   └── gen_js_api_ppx_driver.ml
├── ppx-lib/
│   ├── dune
│   ├── gen_js_api_ppx.ml
│   └── gen_js_api_ppx.mli
├── ppx-standalone/
│   ├── dune
│   ├── gen_js_api.ml
│   └── gen_js_api.mli
└── ppx-test/
    ├── binding.mli
    ├── binding_automatic.mli
    ├── binding_explicitly_automatic.mli
    ├── binding_manual.mli
    ├── dune
    ├── expected/
    │   ├── binding.ml
    │   ├── binding_automatic.ml
    │   ├── extension.ml
    │   ├── first_class_modules.ml
    │   ├── issues.ml
    │   ├── issues_mli.ml
    │   ├── modules.ml
    │   ├── recursive_modules.ml
    │   ├── scoped.ml
    │   ├── types.ml
    │   └── union_and_enum.ml
    ├── extension.ml
    ├── first_class_modules.mli
    ├── issues.ml
    ├── issues_mli.mli
    ├── modules.mli
    ├── ppx/
    │   ├── dune
    │   └── main.ml
    ├── recursive_modules.mli
    ├── scoped.mli
    ├── types.ml
    └── union_and_enum.mli

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: daily


================================================
FILE: .github/workflows/workflow.yml
================================================
name: Builds, tests & co

on:
  - push
  - pull_request

permissions: read-all

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - macos-latest
          - windows-latest
        ocaml-compiler:
          - 5
          - 4
        include:
          - os: ubuntu-latest
            ocaml-compiler: "4.13"

    runs-on: ${{ matrix.os }}

    steps:
      - name: Checkout tree
        uses: actions/checkout@v6

      - name: Set-up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: latest

      - name: Set-up OCaml
        uses: ocaml/setup-ocaml@v3
        with:
          ocaml-compiler: ${{ matrix.ocaml-compiler }}

      - run: opam install . --deps-only --with-test

      - run: opam exec -- make

      - run: opam exec -- make test

  # lint-doc:
  #   runs-on: ubuntu-latest
  #   steps:
  #     - name: Checkout tree
  #       uses: actions/checkout@v6
  #     - name: Set-up OCaml
  #       uses: ocaml/setup-ocaml@v3
  #       with:
  #         ocaml-compiler: 5
  #     - uses: ocaml/setup-ocaml/lint-doc@v3

  # lint-fmt:
  #   runs-on: ubuntu-latest
  #   steps:
  #     - name: Checkout tree
  #       uses: actions/checkout@v6
  #     - name: Set-up OCaml
  #       uses: ocaml/setup-ocaml@v3
  #       with:
  #         ocaml-compiler: 5
  #     - uses: ocaml/setup-ocaml/lint-fmt@v3

  lint-opam:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout tree
        uses: actions/checkout@v6
      - name: Set-up OCaml
        uses: ocaml/setup-ocaml@v3
        with:
          ocaml-compiler: 5
      - uses: ocaml/setup-ocaml/lint-opam@v3


================================================
FILE: .gitignore
================================================
gen_js_api.install
ojs.install
*.merlin
_build
_opam
.vscode


================================================
FILE: .ocp-indent
================================================
match_clause=4
strict_with=auto


================================================
FILE: CHANGES.md
================================================
Changelog
=========

Unreleased
----------

- Support for binding to js_of_ocaml runtime primitives via `@`-prefixed payloads on `[@@js.global]` and `[@@@js.scope "@..."]`, enabling generated bindings to target values supplied by the JavaScript runtime.
- Test suite updates adapted for wasm_of_ocaml.

Version 1.1.6
-------------

- GPR#181: Upgrade ppxlib dependency to 0.37.0 (=> support OCaml 5.4)

Version 1.1.5
-------------

- GPR#180: Fix for OCaml 5.3.0

Version 1.1.4
-------------

- GPR#176: Remove references to joo_global_object (@hhugo)
- GPR#175: Support for simple module construction (@sbriais)

Version 1.1.3
-------------

- GPR#173: Compatibility with Wasm_of_ocaml (@vouillon)
- GPR#171: Update build badge and remove unused travis config (@tmcgilchrist)


Version 1.1.2
-------------

- GPR#170: Make Ojs.iter_properties compatible with jsoo/effects (@vouillon)

Version 1.1.1
-------------

- GPR#167: Fix CI (@cannorin)
- GPR#166: Support first class modules to treat type variables safely (@cannorin)

Version 1.1.0
-------------

- GPR#164:  Switch to js_of_ocaml.4.0 (@hhugo)
- GPR#165:  Allow n-ary constructors in [@js.union] (@cannorin)

Version 1.0.9
-------------

- GPR#161: Fix broken link to VALUES.md (@joelburget)
- GPR#154: Upgrade to ocaml/setup-ocaml@v2 (@smorimoto)
- GPR#153: Support recursive modules (@cannorin)
- GPR#152: [@@js.invoke] attribute to call the global object as a function (@cannorin)

Version 1.0.8
-------------

- GPR#149: Stop using OMP directly (@mlasson)
- GPR#145: Add support for "newable" functions to [@@js.apply] (@cannorin)
- GPR#143: Disable eta reduction for of_js and to_js of type aliases (@cannorin)
- GPR#144: Disable "Spurious js.\* attribute" error for @js.dummy (@cannorin, @mlasson)
- GPR#146: Fix an edge-case bug of prepare_args


Version 1.0.7
-------------

- GPR#140: Adds a deprecation warning the automatic heuristic is used (@mlasson)
- GPR#139: Rename things for backward compatibility (@mlasson)
- GPR#135: UTF-8 support for (Ojs.get/set/delete) adaptions (@mlasson)
- GPR#132: Add support for indexers and "callable" objects (@cannorin)
- GPR#130: Javascript -> JavaScript (@smorimoto)
- GPR#129: Add GitHub Actions workflow (@smorimoto)
- GPR#128: Bucklescript -> ReScript (also add genType ppx as a resource) (@ryyppy)
- GPR#127: Support boolean "enum"s and boolean union discriminators (@cannorin)
- GPR#125: js.custom attribute for type declaration to support custom mapping #125 (@cannorin)
- GPR#123: Upgrade ppx to the ocaml 4.11 ast (@hhugo)
- GPR#120: Split runtime library to own package (@rgrinberg)
- GPR#118: Add ppx tests setup (@jchavarri, @mlasson)
- GPR#115: Support for functors and module inclusion (@mlasson)
- GPR#114: Dependency tweaks (@rgrinberg)
- GPR#113: Add support for type variables (@jchavarri, @mlasson)
- GPR#111: Better ppxlib integration (@hhugo)
- GPR#110: Include payload in extension node (@nojb)

Version 1.0.6
-------------

- GPR #101: Adds travis support + use ocaml-migrate-parsetree (@mlasson)
- GPR #94: Typo: correct wrong 'apply_arr' to 'apply' (@facelesspanda)
- GPR #89: Update the opam file (@hhugo)
- GPR #87: Switch to dune (@hhugo)
- GPR #88: Fix some warnings (@hhugo)
- GRP #85: Adapt to 4.08 (@nojb)

Version 1.0.5
-------------

- Adapt to OCaml 4.06


Version 1.0.4
-------------

- Adapt to OCaml 4.05.


================================================
FILE: CLASSES.md
================================================
Class wrapping in gen_js_api
============================

gen_js_api can bind JavaScript objects into OCaml abstract types with
associated functions (to get/set property and to call methods).  This
form of binding is quite efficient, since the opaque OCaml values are
just the underlying JavaScript objects, with no mapping or wrapping.
In addition to that, gen_js_api provides ways to **wrap JavaScript
objects into OCaml objects**.  This adds some runtime overhead, but
allows users to use standard OO syntax in OCaml and to rely on
inheritance (to mimic similar hierarchy on the JS side).

In addition to the runtime overhead, wrapping JS objects as OCaml
objects also forces to define all methods at once.  With opaque
bindings, methods of a given JS "class" can be spread over multiple
OCaml modules.  This can be especially useful to mimic the behavior of
JS library addins that extends the library's object prototype with
more methods.




Class wrapping
--------------

An interface processed by js_of_ocaml can define an OCaml class used
to wrap some JavaScript objects:

    ````
    class my_class: Ojs.t ->
      object
        inherit Ojs.obj
        (* method declarations *)
        ....
      end
    ````

The class must inherit from `Ojs.obj` directly or indirectly.  This class
simply defines a `to_js` method (returning the underlying `Ojs.t` object).

Such a class declaration produces in the implementation a class
definition with the list of `inherit` clauses (passing the `Ojs.t`
handle to each of them) and a definition for all listed methods.  It
also produces a standard pair of `*_to_js`/`*_of_js` functions (the
`*_to_js` function calls the `to_js` method inherited from `Ojs.obj`,
and `*_of_js` calls the constructor of the class).


Method binding
--------------

- Property getter:

  ````
    method foo: t
       [@@js.get "foo"]
  ````


- Property setter:

  ````
    method set_foo: t -> unit
       [@@js.set "foo"]
  ````


- Method call:

  ````
    method f: t -> unit
      [@@js.call "f"]
  ````

As always, the names can be omitted if they correspond to the implicit
naming scheme.

Prior to version 1.0.7, as for value bindings, some implicit rules applied,
so that `[@@js.*]` attributes could often be omitted (in particular, in
all the examples above).

The following rules were applied in order:

- If the method is a function with one argument `t -> unit` and its
  name starts with `set_`, then the declaration is assumed to be a
  `[@@js.set]` property setter (on the property whose name is obtained
  by dropping the `set_` prefix).

- If the method is a function, then the definition is assumed to be a
  `[@@js.call]` method call.

- Otherwise, the method is assumed to be a `[@@js.get]` property getter.

But since version 1.0.7, *this feature has been deprecated*; all method
should be explicitly annotated or a preprocessor warning will be emitted.

Constructors
------------

The default constructor for a class wrapper is necessarily an `Ojs.t` object
(see above).  (Note: it would be easy to allow such classes to take a
value of an arbitrary JS-able type, but this would make it more
difficult to support inheritance.)

It is possible to bind to actual JS constructors declarations such as:

 ````
  class foo: string -> my_class
 ````

Calling this constructor is then implemented by calling the JavaScript
constructor of the same name, and wrapping the resulting object with
the `my_class` wrapper.  This is similar to defining:

  ````
    val foo: string -> my_class
      [@@js.new]
  ````

but allows writing `new foo(...)` instead of `foo(...)`.

A custom name can be provided with a `[@@js.new]` attribute:

 ````
  class foo: string -> my_class
    [@@js.new "MyConstr"]
 ````


================================================
FILE: IMPLGEN.md
================================================
gen_js_api: generate implementations from interfaces
====================================================

The primary operating mode for gen_js_api is to generate .ml
implementation from annotated .mli interfaces.  These interfaces must
follow a certain shape.  They describe both the JavaScript components
to be imported and how they should be reflected within OCaml.

Usage
-----


```
  $ gen_js_api my_module.mli
```

or with findlib:

```
  $ ocamlfind gen_js_api/gen_js_api my_module.mli
```

This generates my_module.ml.



Supported declarations
----------------------

Interfaces processed by gen_js_api can currently contain:

  - [Type declarations](TYPES.md):

    ````
    type t = ...
    ````

    See [this page](TYPES.md) for a description of supported types.
    Such a type declaration produces in the implementation an identical
    defininition, and associated `*_to_js` and `*_of_js` functions
    (which can be manually exported if needed).


  - [Value declarations](VALUES.md):

    ````
    val f: tyexpr
    ````

    This produces in the implementation a definition for such a value,
    whose content depends on three elements: the name of the value
    (`f` in the example), its declared type (`tyexpr`), and possible
    `[@@js.xxx]` attributes attached to the declaration in the interface.

    See [this page](VALUES.md) for supported forms of value declarations.


  - Sub-modules:

    ````
    module M : sig
      ...
    end
    ````

    This naturally produces in the implementation a corresponding sub-module:

    ````
    module M = struct
      ...
    end
    ````

  - Module aliases:

    If a module alias is declared in the interface, like:

    ```ocaml
    module M = <Module Path>
    ```

    it is directly reflected in the generated implementation without modifications.

  - Module inclusion:

    To include a module `M` in the generated implementation, simply add

    ```ocaml
    include (module type of M)
    ```
    in the corresponding interface.

  - [Class declarations](CLASSES.md)



Verbatim sections
-----------------

A floating attribute `[@@@js.stop]` tells the tool to ignore the
remaining items until the end of the current (possibly nested)
signature.  This can be reverted with a floating attribute
`[@@@js.start]`.  This system makes it possible to specify fragments
of the interface that should not generate any code in the
implementation.

A floating `[@@@js.implem ...]` tells the tool to generate some custom
code in the implementation. The payload `...` is an OCaml structure,
which is processed in the same way as in [ppx mode](PPX.md).


Example:

```ocaml

  [@@@js.stop]
     val foo: int -> unit
  [@@@js.start]

  [@@@js.implem

       val foo_internal: string -> int -> unit
         [@@js.global "foo"]
       let foo = foo_internal ""

  ]
```


For the common case where verbatim sections are used to create custom
value bindings, a `[@@js.custom]` attribute can be applied to a `val`
declaration.  The effect is that the `val` declaration itself is ignored
(nothing is generated in the implementation), and a structure can be
provided as the payload of the attribute.  The example above is equivalent
to:

```ocaml
  val foo: int -> int
  [@@js.custom
       val foo_internal: string -> int -> unit
         [@@js.global "foo"]
       let foo = foo_internal ""
  ]
```

and to:

```ocaml
  val foo: int -> int
  [@@js.custom]

  [@@js.implem
        ...
  ]
```


================================================
FILE: INSTALL_AND_USE.md
================================================
gen_js_api: installation and usage instructions
===============================================


Dependencies
------------

gen_js_api does not have any external build-time dependency except
the OCaml compiler (version 4.03).  Of course, it will be used
in conjuncion with the js_of_ocaml compiler and runtime support.


Installation (with OPAM)
------------------------

````
opam install gen_js_api
````

Or, to track the development version:

````
opam pin add gen_js_api https://github.com/LexiFi/gen_js_api.git
````

Manual installation
-------------------

````
git clone https://github.com/LexiFi/gen_js_api.git
cd gen_js_api
make all
make install  # assuming opam-installer is installed
````

Usage (with dune)
-----------------

 - Invoking the [standalone tool](IMPLGEN.md) (`.mli` -> `.ml` generator):

   ```
   (rule
     (targets my_unit.ml)
     (deps my_unit.mli)
     (action (run %{bin:gen_js_api} %{deps})))
   ```

 - Compiling binding (`.mli` and generated `.ml` files), user
   code which rely on the `Ojs` or with the [ppx processor](PPX.md):

   ```
   (executables
     (names test_jquery)
     (js_of_ocaml)
     (libraries ojs js_of_ocaml)
     (preprocess (pps gen_js_api.ppx))
     (modes byte)
   )
   ```

 - Compiling into JavaScript: Just ask dune to build the `*.bc.js`
   target. (e.g. `dune build test_jquery.bc.js`)

Usage (with ocamlfind)
----------------------

 - Invoking the [standalone tool](IMPLGEN.md) (`.mli` -> `.ml` generator):

   ```
   ocamlfind gen_js_api/gen_js_api my_unit.mli
   ```

 - Compiling binding (`.mli` and generated `.ml` files) and user
   code which rely on the `Ojs` module:

   ```
   ocamlfind ocamlc -package gen_js_api my_unit.mli
   ocamlfind ocamlc -package gen_js_api my_unit.ml
   ```

 - Compiling with the [ppx processor](PPX.md):

   ```
   ocamlfind ocamlc -c -package gen_js_api my_prog.ml
   ```

 - Linking the bytecode program:

   ```
   ocamlfind ocamlc -o my_prog -package gen_js_api -linkpkg ...
   ```

 - Compiling into JavaScript:

   ```
   js_of_ocaml -o my_prog.js +gen_js_api/ojs_runtime.js my_prog
   ```


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright 2015 by LexiFi.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: LOW_LEVEL_BINDING.md
================================================
gen_js_api: low-level binding to JavaScript
===========================================

The code generated by gen_js_api relies on a `Ojs` module (the runtime
support library).  In the same way that OCaml `Obj` module exposes
(unsafe) operations to manipulate arbitrary OCaml values (after
casting them to a universal type `Obj.t`), `Ojs` allows to manipulate
arbitrary JavaScript values through an `Ojs.t` universal type.

`Ojs` encourages to think of native JS values as being "foreign"
values, even though in practice, all OCaml values are represented as
JS values when the OCaml code is compiled with js_of_ocaml.  In
particular, `Ojs` does not expose a function allowing to cast an
arbitrary OCaml value to `Ojs.t` (this can always be done with
`Obj.magic`).

`Ojs.t` is similar to `Js.Unsafe.any` type, but it abstracts away from
specific properties of how js_of_ocaml represents OCaml values.  For
instance the fact, that OCaml integers are encoded directly as JS
numbers is not apparent in `Ojs`, and if this property was to change,
client code would be unaffected.

Abstracting away from js_of_ocaml encoding would also make it easy to
change the way OCaml and JS are connected (either because of changes
in js_of_ocaml's encoding of OCaml values, or because an entirely
different technology is used, such as an OCaml bytecode interpreter
written in JavaScript or a JavaScript engine linked with native OCaml
code).

Note that code generated by gen_js_api doesn't depend on js_of_ocaml's
standard library (`Js` module), only on js_of_ocaml's runtime system.
Our local `Ojs` interface maps directly to primitives provided by
js_of_ocaml's runtime.


Users of gen_js_api would not use `Ojs` very often, except to define
"opaque sub-types" of `Ojs.t` in order to represent JS "classes" or
"interfaces":

```ocaml
type t = private Ojs.t
```

Occasionnaly, it it useful to go down to `Ojs` in order to define
**custom mappings** between JS and OCaml.  For instance, one can
define a type for association lists indexed on strings in OCaml that
are mapped to JS objects:

```ocaml
module Dict : sig
  type 'a t = (string * 'a) list
  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
end = struct
  type 'a t = (string * 'a) list

  let t_to_js ml2js l =
    let o = Ojs.empty_obj () in
    List.iter (fun (k, v) -> Ojs.set o k (ml2js v)) l;
    o

  let t_of_js js2ml o =
    let l = ref [] in
    Ojs.iter_properties o
      (fun k -> l := (k, js2ml (Ojs.get o k)) :: !l);
    !l
end
```


================================================
FILE: Makefile
================================================
# The package gen_js_api is released under the terms of an MIT-like license.
# See the attached LICENSE file.
# Copyright 2015 by LexiFi.

.PHONY: all examples test test-promote clean install uninstall doc reindent publish

all:
	dune build @install @DEFAULT

examples:
	dune build @examples/DEFAULT

doc:
	dune build @doc

test:
	dune build @runtest

test-promote:
	dune build @runtest --auto-promote

clean:
	dune clean

PREFIX := $$(opam config var prefix)

install:
	opam-installer --prefix $(PREFIX) gen_js_api.install

uninstall:
	opam-installer -u --prefix $(PREFIX) gen_js_api.install

reindent:
	git ls-files *.ml *.mli | grep -v expected | xargs ocp-indent -i

VERSION := $$(opam show . | grep "^version" | sort -u | sed 's/version *//')

publish: all
	echo "Publishing v$(VERSION) ..." 
	git tag -a v$(VERSION)
	git push origin v$(VERSION)
	opam publish



	
	


================================================
FILE: NAMING.md
================================================
gen_js_api: default naming convention
=====================================

JavaScript names corresponding to bound components can always be
specified explicitly (with the use of attributes).  When the naming is
left implicit, a JavaScript name is automatically derived from the
OCaml name by applying the following rules:

  1. uppercasing every character following an underscore;

  2. removing every underscore;

  3. uppercasing the first character when generating object constructor names.

This automatic naming convention can be partially disabled by adding
an attribute `[@js.verbatim_names]` on outer structures. When the attribute
`[@js.verbatim_names]` is inherited from the context, the rule 1 and 2 are
disabled.

For instance,

```ocaml
type myType = { x_coord : int; y_coord : int [@js "Y"]}
```

is mapped to a JS record with two fields named "xCoord" and "Y" whereas

```ocaml
type myType = { x_coord : int; y_coord : int [@js "Y"]} [@@js.verbatim_names]
```

is mapped to a JS record with two fields named "x_coord" and "y".


================================================
FILE: NODE_RUNTIME_BINDINGS.md
================================================
# Binding Node.js Modules with Runtime Primitives

This guide shows how to use the new runtime primitive support in `gen_js_api` to bind Node.js libraries that are usually obtained with `require(...)`. The feature hinges on two additions:

- any `[@@js.global "@primitive_name"]` binding returns an `Ojs.t` pointing to a primitive exported by the JavaScript runtime;
- a scope string that starts with `@` (for example `[@@@js.scope "@node_fs.promises"]`) resolves the first path component through the runtime primitives before following regular properties.

Together, those tools let you keep your bindings declarative while delegating the actual `require` calls to a tiny JavaScript stub.

## Example layout

```
runtime_primitives/
  dune
  imports.js
  imports.wat
  bindings.mli
  example.ml
```

### Step 1 - expose the runtime primitives

Create a JavaScript file that `require`s the Node modules you need and publishes them as js_of_ocaml runtime primitives. The js_of_ocaml linker recognises `//Provides: <name>` comments and registers the value under that name at startup.

```javascript
// runtime_primitives/imports.js
'use strict';

//Provides: node_path
var node_path = require('path');

//Provides: node_fs
var node_fs = require('fs');

//Provides: node_version
var node_version = require('process').version;

//Provides: node_console
var node_console = console.log;

```

When targeting WebAssembly you also need to expose the primitives through a `.wat` shim so that `wasm_of_ocaml` can import them at runtime:

```wat
;; runtime_primitives/imports.wat
(global (export "_node_path") (import "js" "node_path") anyref)
(global (export "_node_fs") (import "js" "node_fs") anyref)
(global (export "_node_version") (import "js" "node_version") anyref)
(global (export "_node_console") (import "js" "node_console") anyref)
```

List this file in your dune stanza so that js_of_ocaml ships it with the compiled artefacts:

```
; runtime_primitives/dune
(rule
 (targets bindings.ml)
 (deps bindings.mli)
 (action (run gen_js_api %{deps})))

(executable
 (name example)
 (libraries ojs)
 (preprocess (pps gen_js_api.ppx))
 (modes js wasm)
 (js_of_ocaml (javascript_files imports.js))
 (wasm_of_ocaml (javascript_files imports.js imports.wat)))
```

Adding the file to both `js_of_ocaml` and `wasm_of_ocaml` makes the primitives available in browser and wasm builds alike.

### Step 2 - bind module functions with `[@js.scope "@..."]`

Use `module [@js.scope "@primitive"]` blocks to call methods on runtime primitives without manually threading the module objects. The interface below covers the synchronous filesystem API used in the reference JavaScript while keeping the underlying modules abstract.

```ocaml
(* runtime_primitives/bindings.mli *)
module [@js.scope "@node_fs"] Fs : sig
  val write_file_sync : string -> string -> unit [@@js.global "writeFileSync"]
  val read_file_sync : string -> encoding:string -> string [@@js.global "readFileSync"]
  val readdir_sync : string -> string array [@@js.global "readdirSync"]
  val append_file_sync : string -> string -> unit [@@js.global "appendFileSync"]
end

module [@js.scope "@node_path"] Path : sig
  val separator: string [@@js.global "sep"]
  val join : (string list [@js.variadic]) -> string [@@js.global "join"]
end
```
Each module-level scope starts with `@`, so the ppx turns calls like `Fs.write_file_sync` into direct invocations on the corresponding Node module (`node_fs.writeFileSync` in this case) without requiring you to pass the module object around.

### Step 3 - bind direct values with `@`-prefixed `[@@js.global]`

When you only need the primitive itself—such as a constant exported by a Node module—use the `@` prefix inside `[@@js.global]` to obtain it directly as an OCaml value.

```ocaml
(* runtime_primitives/primitives_bindings.mli continued *)

val node_version : string [@@js.global "@node_version"]
val log : string -> unit [@@js.global "@node_console"]
```

These expand to `Jsoo_runtime.Js.runtime_value ...` calls and convert the results to the requested OCaml types, so you can expose constants or functions alongside the scoped modules described above.

### Step 4 - port the JavaScript example

`main.ml` mirrors the original JavaScript snippet that writes, reads, appends, and re-reads a file while logging progress to the Node console. It relies on the scoped `Fs`/`Path` modules plus the direct `log`, `path_separator`, and `node_version` values.

```ocaml
open Bindings

let initial_content = "Hello, Node.js!"
let appended_line = "\nAppending a new line."
let encoding = "utf-8"
let filename = "example.txt"

let run () =
  let file = Path.join ["."; filename] in

  Fs.write_file_sync file initial_content;

  let content = Fs.read_file_sync file ~encoding in
  if content <> initial_content then
    failwith "Unexpected initial content";
  log ("File content: " ^ content);

  let files = Fs.readdir_sync "." |> Array.to_list in
  if not (List.mem filename files) then
    failwith "example.txt missing from directory listing";
  log ("Files in current directory: " ^ String.concat ", " files);

  Fs.append_file_sync file appended_line;

  let updated = Fs.read_file_sync file ~encoding in
  if updated <> initial_content ^ appended_line then
    failwith "Append failed";
  log ("Updated content: " ^ updated);
  log ("Path separator reported by Node: " ^ Path.separator);
  log ("Node.js version: " ^ node_version)


let () = run ()
```

### Putting it together

1. Declare each required Node module once in `imports.js` (and mirror them in `imports.wat` for wasm) using the js_of_ocaml `//Provides:` convention.
2. Export the files through dune so that the js_of_ocaml toolchain registers those primitives at runtime.
3. Map node modules in OCaml with `module [@js.scope "@primitive"]` blocks, and use `@`-prefixed `[@@js.global]` bindings for direct values.
4. Consume the generated modules from OCaml exactly as you would in JavaScript, as shown in `example.ml`.

With these pieces in place you can keep writing high-level `gen_js_api` bindings while relying on the new runtime primitive support to bridge your OCaml code to Node-specific libraries provided via `require`.


================================================
FILE: PPX.md
================================================
gen_js_api: ppx mode
====================

While the primary mode of operation for gen_js_api is to generate an
.ml file from an annotated .mli file, it is also possible to use it as
a ppx preprocessor on an .ml file directly to insert local JS bindings.

The `-ppx` command-line option must be the first argument passed
to gen_js_api to enable the ppx mode:

```
  $ ocamlc -c -ppx "gen_js_api -ppx" my_prog.ml
```

or with findlib:

```
  $ ocamlfind ocamlc -c -package gen_js_api my_prog.ml
```


Note: the ppx currently does nothing on `.mli` files.


Several forms are supported:

 - `[%js: <signature>]` extension as a module expression.  Examples:

   ````
     include [%js: <signature>]

     module M = [%js: <signature>]
   ````

   The signature is processed as if it were found in an .mli file, and
   the resulting structure is inserted in place of the `[%js: ...]`
   extension.  See [this page](IMPLGEN.md) for a list
   of declarations supported in such interfaces.

 - `[@@js]` attributes on type declarations.

   Example:

   ````
     type t = { x : int; y : int } [@@js]
   ````

   This generates the corresponding `*_of_js` and `*_to_js` functions.
   In case of a multi-type declaration, each type must be annotated
   with `[@@js]` (if needed). See [this page](TYPES.md) for a description
   of support forms of type declarations.

 - `[%js.to: ty]` and `[%js.of: ty]` extensions on expressions.

   Example:

   ````
     let x : Ojs.t = [%js.of: int list]  [ 10; 20; 30 ]
   ````

   This form generates the mapping function associated to a JS-able type.
   See [this page](TYPES.md) for a description of JS-able type.


================================================
FILE: README.md
================================================
gen_js_api: easy OCaml bindings for JavaScript libraries
========================================================

[![Build Status](https://github.com/LexiFi/gen_js_api/actions/workflows/workflow.yml/badge.svg)](https://github.com/LexiFi/gen_js_api/actions/workflows/workflow.yml)

Overview
--------

gen_js_api aims at simplifying the creation of OCaml bindings for
JavaScript libraries.  It must currently be used with the [js_of_ocaml
compiler](https://github.com/ocsigen/js_of_ocaml), although other ways
to run OCaml code "against" JavaScript might be supported later with
the same binding definitions (for instance,
[Bucklescript](https://github.com/bloomberg/bucklescript),
or direct embedding of a JS engine in a native OCaml application).

gen_js_api is based on the following ideas:

 - Authors of bindings write OCaml signatures for JavaScript libraries
   and the tool generates the actual binding code with a combination
   of implicit conventions and explicit annotations.

 - The generated binding code takes care of translating values between
   OCaml and JavaScript and of dealing with JavaScript calling
   conventions.

 - All syntactic processing is done by authors of bindings: the client
   code is normal OCaml code and does not depend on custom syntax nor
   on JS-specific types.


gen_js_api can be used in two complementary ways:

  - [Generating .ml implementations from annotated .mli interfaces](IMPLGEN.md),
    in order to create the code for stub libraries.

  - As a [ppx preprocessor on implementations](PPX.md) to define local
    bindings.



Examples
--------

The repository contains some examples of OCaml bindings to JavaScript
libraries created with gen_js_api:

 - Very partial [bindings to jQuery](examples/misc/jquery.mli), with
   some [example client code](examples/misc/test_jquery.ml).

 - Partial bindings to JavaScript [strings and
   regexps](examples/misc/js_str.mli) and JavaScript
   [dates](examples/js_date.mli).

 - Some [ad hoc test](examples/test) to exercise various features.

 - An example of a self-contained program, a [simple
   calculator](examples/calc/calc.ml), implementing local .bindings

Documentation
-------------

  - [Install and use](INSTALL_AND_USE.md)
  - [Low-level binding to JavaScript](LOW_LEVEL_BINDING.md)
  - [Using gen_js_api to generate .ml from .mli](IMPLGEN.md)
  - [Using gen_js_api as a ppx processor](PPX.md)
  - [Default naming convention](NAMING.md)
  - [JS-able types and type declarations](TYPES.md)
  - [Value bindings](VALUES.md)
  - [Class-wrapping bindings](CLASSES.md)
  - [TODO list](TODO.md)


Related projects
----------------

  - [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml): The compiler
    and runtime system on which gen_js_api relies. (Note: gen_js_api
    doesn't depend on js_of_ocaml's OCaml library, nor on its language
    extension.)

  - [goji](https://github.com/klakplok/goji): A DSL to describe OCaml
    bindings for JavaScript libraries.

  - [DefinitelyMaybeTyped](https://github.com/andrewray/DefinitelyMaybeTyped):
    A project to parse
    [DefinitelyTyped](https://github.com/borisyankov/DefinitelyTyped)
    interfaces and produce OCaml interfaces.

  - [ReScript](https://github.com/rescript-lang/rescript-compiler):
    Another compiler from OCaml to JavaScript, featuring the [genType](https://github.com/reason-association/genType) ppx for generating TS / Flow types and runtime converters.

About
-----

gen_js_api has been created by LexiFi for porting a web application
from JavaScript to OCaml.  The tool has been used in production since
2015.

This gen_js_api package is licensed by LexiFi under the terms of the
MIT license.

See see [Changelog](CHANGES.md)

Contact: alain.frisch@lexifi.com

Contributors:

 - Alain Frisch
 - Sebastien Briais


================================================
FILE: TODO.md
================================================
TODO list for gen_js_api
========================

- Create reasonably complete bindings for JavaScript's stdlib
  (string, regexp), for the DOM, for jQuery, etc.

- Add a safe mode, where the generated code is augmented with explicit
  checks (e.g. when casting a JS value to a string or integer, when
  accessing a property, etc).

- Optimize generated code (for instance, lift calls to string_of_js on
  literals).

- Idea: to facilitate binding and calling multiple methods at once,
  provide something like (jQuery example):

    ```ocaml
    val set: ?text:string -> ?hide:unit -> ?css:(string * string) -> t -> unit
     [@@js.multicall]
    ```


  One can then write:

     ```ocaml
     set
       ~text:"Hello"
       ~hide:()
       node
     ```

  Each provided argument yields one method call (in the order where
  arguments are declared, of course).  This is mostly interesting when
  methods are used to "set" internal properties, and when the different
  calls commute.

  This could be simulated with:

  ```ocaml

    val set: ?text:string -> ?hide:unit -> ?css:(string * string) -> t -> unit
      [@@@js.custom
      val set_text: t -> string -> unit
        [@@js.meth "text"]

      let set ?text ... x =
        Option.iter (set_text x) text;
        ...
      ]
  ```


- Optional arguments on JS methods are usually at the end.  But this
  forces to add a `unit` pseudo-argument.  One could have an
  (optional) convention to push optional arguments at the end of the JS
  call even though there are not in the OCaml type.  This would also
  work for instance methods:

  ```ocaml
  val foo: ?bla:int -> t -> int
  ```

  instead of:

  ```ocaml
  val foo: t -> ?bla:int -> unit -> int
  ```

- When defining a binding to a function with `[@@js.global
  "foo.bar"]`, this is currently interpreted as calling this global
  function.  One could interpret it as calling the bar method on
  object foo, which would have the effect of assigning `this` during
  the function evaluation.


================================================
FILE: TYPES.md
================================================
Types supported in gen_js_api
=============================

JS-able types
-------------

A JS-able type is an OCaml type whose values can be mapped to and from
JavaScript objects.

The following types are supported out-of-the-box:

 - Basic built-in types: `string`, `int`, `bool`, `float` and `Ojs.t`.

 - Tuples of JS-able types (mapped to JS arrays).

 - Sequences of JS-able types: `array` and `list`, both mapped to JS
   arrays (which are assumed to be indexed by integers 0..length-1).

 - Options on JS-able types.  They are mapped to the same type as
   their parameter: `None` is mapped to JS `null` value, and both
   `null` and `undefined` are mapped back to `None`.  This encoding
   doesn't support nested options in a faithful way.

 - Arrows (see section below).

 - Polymorphic variants with only constant variants are supported
   (see the section on enums below).

 - Polymorphic variants can also be used to encode non-discriminated
   unions on the JS side (see the section on union types below).

 - Polymorphic variants can also be used to encode discriminated
   unions on the JS side (see the section on discriminated union types
   below).

 - Free type variables like `'a`, they will involve no runtime
   mapping when moving between OCaml and JS (see type variable section).

An arbitrary non-parametrized type with path `M.t` is JS-able if the
following two values are available in module `M`:

```ocaml
val t_to_js: t -> Ojs.t
val t_of_js: Ojs.t -> t
```

The name of these values is obtained by appending `_of_js` or `_to_js`
to the local name of the type.  It is thus possible to define JS-able
manually by defining these two functions.  Type and class declarations
processed by gen_js_api (see sections below) create JS-able type (by
generating those functions automatically).

Parametrized types can also be JS-able.  It is currently assumed that
such types are covariant in each of their parameter.  Mapping
functions take extra arguments corresponding to the mapper for each
parameter.  For instance, a type `'a t` would need to come with the following
functions:

```ocaml
val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
```

Arrow types
-----------

Arrow types can also be used in contexts that expect JS-able types.
All arguments must be JS-able types, and a final `unit`
pseudo-argument is allowed (and mandatory when there is no real
argument).  The function's result can be either a JS-able type or
`unit`.  Note that `unit` is not considered as a proper JS-able type:
it is only allowed in these two contexts (as the result, or the final
pseudo-argument).

Arguments can be **labelled or optional**.  Labels are simply ignored
on the JS side.  Optional arguments have different treatments:

 - When mapping an OCaml function to JS (e.g. a callback), optional
   arguments are treated as normal values of an option type (i.e.
   both `null` and `undefined` are mapped to `None`).

 - When mapping a JS function to OCaml, it is possible to specify
   a default value to fill in a missing argument:

   ```ocaml
   val f: t -> ?x:(int [@js.default 0]) -> unit -> t
   ```

   If no default value is provided and the argument is missing, the
   argument is *dropped* from the list of arguments passed to the JS
   call (this apply to function/method/constructor calls).

 - In `[@@js.builder]` values, missing optional arguments are ignored
   (they don't create any property on the object).


There is a special treatment for optional argument on a
`[@js.variadic]` argument (see below), in which case a missing value
is interpreted as an empty list (i.e. no extra arguments).


When mapping an OCaml function to JS, the **function arity** is the
number of real arguments (not counting the final `unit`) and the
semantics is the standard one for JS functions: missing arguments are
filled with `undefined` and extra arguments are dropped.  The correct
way to support a calling convention where the JS caller might not
provide all arguments to a function defined in OCaml is to use
optional arguments (or just arguments with option types) on the OCaml
side.

In order to define **functions that return functions**, one can put a
`[@js.dummy]` attribute (or any arbitrary attribute) on the resulting type :

```ocaml
t1 -> (t2 -> t3 [@js.dummy])
```

Without the attribute, such a type would be parsed as a function of
arity 2 (returning type `t3`).


**Variadic functions** are supported, by adding a `[@js.variadic]`
attribute on the last parameter (which will represent all remaining
arguments):

```ocaml
val sep: string -> (string list [@js.variadic]) -> string
```

Type declarations
-----------------

All type declarations processed by gen_js_api create JS-able types,
i.e.  associated `*_to_js` and `*_to_js` mapping functions.  A
optional "private" modifier is allowed on the type declaration (in the
interface) and dropped from the generated definition (in the
implementation).  Mutually recursive type declarations are supported.


- "Abstract" subtype of `Ojs.t`:

    ```ocaml
    type t = private Ojs.t
    ```

  This is used to bind to JS "opaque" objects, with no runtime mapping
  involved when moving between OCaml and JS (mapping functions are the
  identity).

- Abstract type

   ```ocaml
   type t
   ```

  This will generate `type t = Ojs.t` in the implementation.  This
  is very similar to the case above.

- Type abbreviation:

    ```ocaml
    type t = tyexp
    ```

  (formally, abstract types with a manifest).  This assumes that the
  abbreviated type expression is itself JS-able.  Note that the first
  kind of type declaration above (abstract subtypes of `Ojs.t`) are
  a special kind of such declaration, since `abstract` is always dropped
  and `Ojs.t` is JS-able.

- Record declaration:

    ```ocaml
    type t = { .... }
    ```

  This assumes that the type for all fields are JS-able.  Fields can
  be mutable (but conversions still create copies).
  Polymorphic fields are not yet supported.

  OCaml record values of this type are mapped to JS objects (one
  property per field).  By default, property names are equal to OCaml
  labels, but this can be changed manually with a `[@js]` attribute.

  ```ocaml
  type myType = { x : int; y : int [@js "Y"]}
  ```

- Parametrized Type:

  It is allowed to parametrize types processed by gen_js_api as long as
  type variables does not occur at contravariant positions.

  For instance :
  ```ocaml
    type ('a, 'b) coord = { x : 'a; y : 'b}
  ```
  is accepted while :
  ```ocaml
    type 'a t = 'a -> int
  ```
  is rejected.

- Sum type declaration, mapped to enums (see Enums section).

- Sum type declaration with non constant constructors, mapped to records with a discriminator field (see Sum types section).

- Arbitrary type with custom mappings

  If you want to use a type that is not supported by gen_js_api, you can make it JS-able by providing
  your own `*_of_js` and `*_to_js` functions (custom mappings) with a `[@@js.custom ...]` attribute.

  ```ocaml
  type t = ... [@@js.custom
    {
      of_js = (fun ... -> ...);
      to_js = (fun ... -> ...)
    }
  ]
  ```

  This is particularly useful when the type is mutually recursive with other types which can be processed by gen_js_api.
  See the [section on manually created bindings](LOW_LEVEL_BINDING.md) for more information on writing custom mappings by hand.

  Not to be confused with [the `[@@js.custom]` attribute for `val` declarations](IMPLGEN.md#verbatim-sections).

Enums mapped to polymorphic variants or sum types
-------------------------------------------------

Either polymorphic variants or normal sum types (all with constant
constructors) can be used to bind to "enums" in JavaScript.  By
default, constructors are mapped to the JS string equal to their OCaml
name, but a custom translation can be provided with a `[@js]`
attribute.  This custom translation can be a string or an integer
literal or a float literal.

```ocaml
type t =
  | Foo [@js "foo"]
  | Bar [@js 42]
  | Baz [@js 4.2]
  | Qux
    [@@js.enum]

type t = [`foo | `bar [@js 42] | `baz [@js 4.2] | `Qux] [@@js.enum]
```


It is possible to specify constructors with one argument of
type (int or float or string), used to represent "all other cases" of JS values.

```ocaml
type status =
  | OK [@js 1]
  | KO [@js 2]
  | OO [@js 1.5]
  | OtherS of string [@js.default]
  | OtherI of int [@js.default]
    [@@js.enum]
```

There cannot be two default constructors with the same argument type.
Also, there cannot be default constructors of type int and float at the same time.

Sum types mapped to records with a discriminator field
------------------------------------------------------

Either polymorphic variants or sum types can be mapped to JS records
with a discriminator field.

By default, the name of the discriminator field is `kind`, but this
can be changed by specifying a field name as attribute value of the
`[@@js.sum]` attribute. The value of the discriminator field is set to
the representation of the constructor name: it is derived
automatically from the constructor name but can also be specified with
a `[@js]` attribute. In this latter case, it can be either a string or
an integer.

A constant constructor is simply mapped to a record containing the
discriminator field.

A unary constructor is mapped to a record containing two fields: the
discriminator field and an argument field representing the unique
argument of the constructor. The argument field name is by default
`arg`, but this can be changed with a `[@js.arg]` attribute.

At most one unary constructor may have the attribute `[@js.default]`
and the argument of this constructor must be of type `Ojs.t`. In this
case, this constructor is used to handle the default case when either
the discriminator field is equal to an unexpected value or even worse
when the discriminator field is absent (from JS to ML). In the other
direction (from ML to JS), the unique argument is used as JavaScript
representation.

A nary constructor is mapped to a record containing two fields: the
discriminator field and an argument field set to an array representing
the arguments of the constructor. Once again, the argument field name
is by default `arg`, but this can be changed with a `[@js.arg]`
attribute. In the case of polymorphic variant, if the argument is a
tuple, then the polymorphic variant constructor is considered to be
n-ary.

Finally, an inline record constructor is mapped to a record containing
all the field of the record in addition of the discriminator
field. The name of the fields are derived from the name of the record
fields. As usual, these names can be customized using a `[@js]`
directive. This last case only applies to sum types.

```ocaml
type t =
  | A
  | B of int
  | C of int * string
  | D of {age: int; name: string}
  | Unknown of Ojs.t [@js.default]
    [@@js.sum]
```

The following declaration is equivalent to the previous one.

```ocaml
type t =
  | A [@js "A"]
  | B of int [@js.arg "arg"]
  | C of int * string [@js.arg "arg"]
  | D of {age: int [@js "age"]; name: string}
  | Unknown of Ojs.t [@js.default]
    [@@js.sum "kind"]
```

Union types
-----------

It is common for JS functions to allow arguments of several different
types (for instance, a string or an object).  To represent this calling
convention, one can use polymorphic variants:

```
val f: t -> ([`Str of string | `Obj of t | `Nothing] [@js.union]) -> ...
```

When the `[@js.union]` attribute is used without any other option,
only the ML to JS function is generated. The ML to JS conversion
function simply maps constant constructors to the `null` value,
unary constructors to the value of the constructor argument,
and n-ary constructors to the array of the constructor argument values
(i.e. treated as a tuple).

For generating the converse function, one needs to have a way to
distinguish JS values in the union type. At the moment, union types
with a discriminator field argument are supported. To indicate the
name of the field, one can add extra option `on_field "kind"` (where
"kind" is the name of the field) to the `[@js.union]` attribute. In
this case, the JS to ML conversion function will inspect the value of
the field named "kind" and will map the JS value to the corresponding
unary constructor. As for sum types, the value of the discriminator
field is deduced from the name of the constructors but it can always
be overridden by using a `[@js]`attribute.

```
type close_path

type moveto_abs

type svg_path_seg =
  | Unknown of Ojs.t         [@js.default]
  | Close_path of close_path [@js 1]
  | Moveto_abs of moveto_abs [@js 2]
  [@@js.union on_field "pathSegType"]
```

As for sum types, at most one unary constructor may have the
`[@js.default]` attribute and the argument of this constructor must be
of type `Ojs.t`. In this case, this constructor is used to handle the
default case when either the discriminator field is equal to an
unexpected value or even worse when the discriminator field is absent
(from JS to ML).

Discriminated union types
-------------------------

It is common for JS functions to allow arguments of several different
types (for instance, a string or an object), whose type depends on a
preceding argument.  To represent this calling convention, one can use
polymorphic variants:

```
val f: t -> ([`Str of string | `Obj of t | `Nothing] [@js.enum]) -> ...
```

This generalisation of the `[@js.enum]` attribute can only be used on
polymorphic variant used in contravariant context (i.e. to describe
mapping from OCaml to JavaScript, not the other way around).  With
this calling convention, first the representation of the constructor
(which can be an integer or a float or a string, which is derived
automatically if not specified with a `[@js]` attribute) is passed,
followed by the n arguments of the constructor.

Type variables
--------------

Unbound type variable are processed implicitly coerced from and to
`Ojs.t` using unsafe coercion.

This is useful when writing bindings to JS functions that rely on data structures
that can contain OCaml values as is. For example, to directly use the JS
arrays to store OCaml values in their original runtime representation, a
`JsArray` module could be defined:

```ocaml
module JsArray : sig
  type 'a t = private Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t

  val create: int -> 'a t [@@js.new "Array"]
  val push: 'a t -> 'a -> unit [@@js.call]
  val pop: 'a t -> 'a option [@@js.call]
end
```

**Important:** the functions generated from types with variables will only apply
the identity function when converting to or from JS. So this approach should
never be used to interface with a JS function that expects the types to be
converted. For example, the following would break if we used it as a binding
to the [`Array.join`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join)
function:
```ocaml
val join: string JsArray.t -> string -> string
```
Indeed, the objects contained in the JsArray.t are not JavaScript strings but
representation of caml strings.
To properly do this, we would want the strings contained in the data structure
to be converted /to JS types, this would require conversion functions not
ignoring their first argument that are manually implemented.

One approach is to use functors instead:
```ocaml
(* Ojs.T is defined as follows:

  module type T = sig
    type t
    val t_to_js : t -> Ojs.t
    val t_of_js : Ojs.t -> t
  end
*)

module JsArray (E: Ojs.T): sig
  type t
  val t_to_js: t -> Ojs.t
  val t_of_js: Ojs.t -> t

  val create: unit -> t [@@js.new "Array"]
  val push: t -> E.t -> unit [@@js.call]
  val pop: t -> E.t option [@@js.call]
end

module StringArray : sig
  include (module type of JsArray(Ojs.String))

  val join: t -> string -> string [@@js.call]
end
```
By moving the type parameters to the functor arguments, you can enforce the
value conversion between JS types and OCaml types.

You can also use [first-class modules](VALUES.md#first-class-modules) for value bindings,
which will be used to convert the polymorphic values and thus making the binding safe:
```ocaml
module[@js.scope "console"] Console: sig
  val log: (module[@js] Ojs.T with type t = 'a) -> 'a -> unit [@@js.global]
end
```

You can also create safe bindings manually with the low level functions
provided by `Ojs` module. See the [section on manually created bindings](LOW_LEVEL_BINDING.md)
for more information.



================================================
FILE: VALUES.md
================================================
Value bindings in gen_js_api
============================


Supported forms
---------------

- Method call:

  ```ocaml
  val my_method: t -> T1 -> ... -> Tn -> T
  [@@js.call]
  ```

  Calling the function on a first argument `o` of type `t` corresponds
  to calling the method `myMethod` on the underlying JS object, with
  other arguments passed to it.

  By default, the name of the method on the JS side is derived from
  the name of the OCaml value (`myMethod` above).  It is possible to
  specify a custom name explicitly, for instance for cases where the
  JS name is not a valid OCaml (lowercase-)identifier, or to support
  overloading (exposing multiple OCaml functions that correspond to
  different types given to the same JS method):


  ```ocaml
  val my_method: t -> T1 -> ... -> Tn -> T
  [@@js.call "JavaScriptMethodName"]
  ```

- Function Application

  ```ocaml
  val apply: t -> T1 -> ... -> Tn
  [@@js.apply]
  ```

  Calling the function on a first argument `f` of type `t` corresponds
  to calling the underlying JS function object directly, with
  other arguments passed to it.

  This is particularly useful when binding to a "callable" JS object (an object that is also a function), or [a function type in a TypeScript interface](https://www.typescriptlang.org/docs/handbook/interfaces.html#function-types).

  The name of the function need not necessarily be `apply` as long as the `[@@js.apply]` attribute is present.

  When the function you want to bind is a "newable" one (a function that must be called with a prefix `new`, e.g. constructors), use `[@@js.apply_newable]` instead. This is especially useful to bind to constructor interfaces in TypeScript.

  ```ocaml
  module FooConstructor: sig
    type t
    val new_: t -> Foo.t [@@js.apply_newable]
  end
  val fooConstructor: FooConstructor.t [@@js.global "Foo"]
  ```

  When the "callable" object you want to bind to is a global object, the `[@@js.invoke]`
  attribute along with the `[@js.scope]` attribute (see below) may be used to call it.

  For instance, you can write
  ```ocaml
    module[@js.scope "JavaScriptClassName"] C : sig
      val invoke: T1 -> ... -> Tn -> t [@@js.invoke]
    end

    (* usage *)
    let x = C.invoke arg1 ... argn
  ```
  instead of
  ```ocaml
    module C : sig
      type t
      val apply: t -> T1 -> ... -> Tn -> t [@@js.apply]
    end
    val c: C.t [@@js.global "JavaScriptClassName"]

    (* usage *)
    let x = C.apply c arg1 ... argn
  ```

- Object constructor:

  ```ocaml
  val new_my_class: T1 -> ... -> Tn -> t
  [@@js.new]
  ```

  Corresponds to calling a JS constructor with arguments
  passed to it.

  By default, the name of the class on the JS side is derived from the
  name of the OCaml value (`MyClass` above): in this case, the value
  name must start with the `new_` prefix which is dropped and the
  remaining name is capitalize to obtain the class name.  It is
  also possible to specify a custom name explicitly.

  ```ocaml
  val f: T1 -> ... -> Tn -> t
  [@@js.new "JavaScriptClassName"]
  ```
  As for global values, it is possible to indicate the access path by
  using `[@js.scope]` attributes on englobing modules (see below).

  When the global object is itself an object constructor, the `[@@js.create]`
  attribute may be used to instantiate it.

  For instance,
  ```ocaml
    module[@js.scope "JavaScriptClassName"] C : sig
      val create: T1 -> ... -> Tn -> t [@@js.create]
    end
  ```
  is the same as
  ```ocaml
    module C : sig
      val create: T1 -> ... -> Tn -> t [@@js.new "JavaScriptClassName"]
    end
  ```

- Global value or function:

  ```ocaml
  val x: t
  [@@js.global]
  ```

  This creates an OCaml value that corresponds to a globally accessible
  JavaScript value.  This is used to access both global objects (e.g.
  the `window` object) and global functions (e.g. `alert`).  It is also
  possible to specify a custom name for the JavaScript variable:

  ```ocaml
  val x: t
  [@@js.global "JavaScriptValueName"]
  ```

  Example:
  ```ocaml
  val alert: string -> unit
  [@@js.global]
  ```

  By default, a global value or function is taken from the global
  object. However, it is possible to specify an access path by using
  `[@js.scope]` attribute on englobing modules (see the Scope section).

- Property getter

  ```ocaml
  val prop: t -> T
  [@@js.get]
  ```

  Calling the function on a first argument `o` of type `t` corresponds
  to getting the `prop` property of the underlying JS object. A custom
  name for the JS property can be specified:

  ```ocaml
  val get_property: t -> T
  [@@js.get "MyProp"]
  ```


- Property setter

  ```ocaml
  val set_prop: t -> T -> unit
  [@@js.set]
  ```

  Calling the function on a first argument `o` of type `t` corresponds
  to setting the `prop` property of the underlying JS object.  Note that
  the value name must start with the `set_` prefix, which is dropped to
  obtain the property name.

  A custom name for the JS property can also be specified (in which
  case the name of the value can be arbitrary):

  ```ocaml
  val modify_prop: t -> T -> unit
  [@@js.set "prop"]
  ```

- Index getter

  ```ocaml
  val get: t -> index -> T option
  [@@js.index_get]
  ```

  Corresponds to getting from an index accessor or [an index signature in a TypeScript interface](https://www.typescriptlang.org/docs/handbook/interfaces.html#indexable-types).

  The return type may be `T` or `T option`, depending on whether the property is optional or not.

  The name of the function need not necessarily be `get` as long as the `[@@js.index_get]` attribute is present.

  `index` must be `int`, `string`, or abstract types holding a JavaScript `number` or `string` value.

- Index setter

  ```ocaml
  val set: t -> index -> T -> unit
  [@@js.index_set]
  ```
  Corresponds to setting to an index accessor or [an index signature in a TypeScript interface](https://www.typescriptlang.org/docs/handbook/interfaces.html#indexable-types).

  The name of the function need not necessarily be `set` as long as the `[@@js.index_set]` attribute is present.

  `index` must be `int`, `string`, or abstract types holding a JavaScript `number` or `string` value.


- Global getter

  ```ocaml
  val get_x: unit -> T
  [@@js.get "x"]

  val get_sub_x: unit -> T
  [@@js.get "MyObject.x"]
  ```

  This creates a function which returns the current value of a
  global variable or of a (possibly nested) inner field of a global variable.

  As for global values, it is possible to indicate the access path by
  using `[@js.scope]` attributes on englobing modules.

- Global setter

  ```ocaml
  val set_x: T -> unit
  [@@js.set "x"]

  val set_sub_x: T -> unit
  [@@js.set "MyObject.x"]
  ```

  This creates a function which sets the value of a
  global variable or of a (possibly nested) inner field of a global variable.

  As for global values, it is possible to indicate the access path by
  using `[@js.scope]` attributes on englobing modules.

- Cast

  ```ocaml
  val cast: t1 -> t2
  [@@js.cast]
  ```

  Calling this function performs an unchecked cast from type `t1` to
  type `t2`, going through the JavaScript representation (i.e.
  applying mapper from `t1` to the underlying JS object, and back
  using the mapper for `t2`).


- Literal object builder:

  ```ocaml
  val make: l1:T1 -> ... -> ln:tn -> t
  [@@js.builder]
  ```

  Corresponds to creating a JS plain object with fields initialized
  with the provided values.  The name of the function (`make` in the
  example) does not correspond to any concept in JS.  By default, the
  JS field names are derived from OCaml labels, but it is also
  possible to override that with a `[@js]` attribute on the argument's
  type.  All fields must be labeled or optional, or come with such an
  attribute.

  Optional arguments (but not non-optional argument with optional
  type) are treated in a special way: no field is created in the JS
  object if the parameter is not provided on the call site (without
  this special behavior, the treatment would be to set the field to
  `null`, which is the encoding of `None`).

  Example:

  ```ocaml
  type t  = private Ojs.t

  val mk: ?children:t list -> age:int -> (string[@js "name"]) -> t
  [@@js.builder]
  ```


- Custom binding:

  ```ocaml
  val f: ...
    [@@js.custom
          let f = ...
    ]
  ```

  The val declaration itself doesn't produce anything in the
  implementation.  Instead, custom OCaml code that goes into the
  implementation must be provided explicitly.

  See [Verbatim section](IMPLGEN.md) for more details and examples.

Calling a function/constructor by different means
-------------------------------------------------

|                                     | as a function          | as a constructor       |
|-------------------------------------|------------------------|------------------------|
| call the first argument             | `[@@js.apply]`         | `[@@js.apply_newable]` |
| call the global object              | `[@@js.invoke]`        | `[@@js.create]`        |
| call a member of the first argument | `[@@js.call "methodName"]`   | N/A                    |
| call a member of the global object  | `[@@js.global "funcName"]` | `[@@js.new "ClassName"]`    |

Scope
-----

The signature attribute `[@@@js.scope "property"]` changes the reference to the current global
object by following the property provided as payload. Nested scopes work as if the
access path were composed by concatenation of all the names indicated by [@js.scope]
attribute, separated by a '.'.

A simple use case is to bind to JavaScript values packed in singleton objects or classes.

For instance,

```ocaml
  module[@js.scope "console"] Console: sig
    val log: string -> unit [@@js.global]
  end
```

is equivalent to

```ocaml
  module Console: sig
    val log: string -> unit [@@js.global "console.log"]
  end
```

When attached directly to a module, the payload of `[@@js.scope]`
may be omitted, it will be implicitly filled with the module name
(preserving the capitalization !).

Before version 1.0.7, the presence of `[@@js.scope]` used to change
the behavior of automatic bindings. It is no longer the case.

An experimental feature also allows to pass an expression of type `Ojs.t` as
a payload to replace the global object. The intended use case is to allow
dynamic loading of modules.

There is also a tuple notation `[@js.scope (s1, ..., sn)]` that helps
writing nested scopes. It is equivalent to `[@js.scope sn]...[@js.scope s1]`.

For instance, the following annotated modules will generate the same code:
```ocaml
  module NestedScope0 : sig
    val f: string -> unit [@@js.global "outer.inner.f"]
  end
  module [@js.scope ("outer", "inner")] NestedScope1 : sig
    val f: string -> unit [@@js.global]
  end
  module NestedScope2 : sig
    val f: string -> unit [@@js.global]
  end [@js.scope "inner"] [@js.scope "outer"]
```

First-class modules
-------------------

As introduced in [Type variables](TYPES.md#type-variables), you can use
first-class modules to enforce JS/OCaml value conversion on polymorphic functions.

```ocaml
module[@js.scope "console"] Console: sig
  val log: (module[@js] Ojs.T with type t = 'a) -> 'a -> unit [@@js.global]
end
```

There are several restrictions when using first-class modules:

* First-class modules must be annotated with `@js`.
  - This attribute indicates that it should only be used to convert values
    and should not be passed directly to the JS function.

* First-class modules must come before any other normal types.
  - The following is invalid because the first-class module comes after a normal type `'a`:
    ```ocaml
    val log: 'a -> (module[@js] Ojs.T with type t = 'a) -> unit [@@js.global]
    ```

* A first-class module to convert a type variable `'x` must be in the form of
  `(module[@js] Ojs.T with type t = 'x)`.
  - The following is invalid because it has a different form (though the meaning is equivalent):
    ```ocaml
    module type MyOjsT = Ojs.T

    val log: (module[@js] MyOjsT with type t = 'a]) -> 'a -> unit [@@js.global]
    ```

* First-class modules can't be used outside of value bindings.
  - The following is invalid because it is used in a type alias:
    ```ocaml
    type 'a logger = (module[@js] Ojs.T with type t = 'a) -> 'a -> unit

    val log: 'a logger [@@js.global]
    ```

To use bindings with first-class modules, you just have to pass the enclosing modules of the types:
```ocaml
module[@js.scope "Person"] Person : sig
  type t

  (* these functions must be present *)
  val t_to_js: t -> Ojs.t
  val t_of_js: Ojs.t -> t

  val create: string -> t [@@js.create]
end

let p = Person.create "Foo";;

Console.log (module Person) p;; (* Person { name: 'Foo' } *)
```

For built-in types, there are pre-defined modules available in the `Ojs` module:
```ocaml
Console.log (module Ojs.String) "hello, world!";;
Console.log (module Ojs.Int) 42;;
Console.log (module Ojs.List(Ojs.String)) ["hello"; "world!"];;
```

Automatic binding (Deprecated since 1.0.7)
------------------------------------------

Some conventions, based on the declared value names and their types,
allow to infer implicitly the `[@@js.xxx]` attributes on value
declarations in most cases.

*This feature has been deprecated starting from version 1.0.7*. All values
declaration should be annotated with an explicit attribute. Otherwise
a preprocessor warning will be emitted.

Note that in all modes the declaration of conversion functions generated
from types are ignored in order to expose the generated functions.

This means all value of declarations of the form:
```ocaml
val τ_to_js: ... -> Ojs.t
```
or the form
```ocaml
val τ_of_js: ... -> τ
```

The rules are applied in order:

- If the value is a function whose result is a named type `... -> τ`
  and the name is `create`, then the declaration is assumed to
  be a `[@@js.create]` object creation.

- If the value is a function whose result is a named type `... -> τ`
  and its name starts with `new_`, then the declaration is assumed to
  be a `[@@js.new]` object creation (on the class whose name is
  obtained by dropping the `new_`prefix).

- If the value is a function with a single argument `τ1 -> unit` and
  its name starts with `set_`, then the declaration is assumed to be a
  `[@@js.set]` global setter (whose name is obtained by dropping the
  `set_` prefix).

- If the value is a function returning `unit` with three arguments
  whose first argument is a named type `τ -> τ2 -> τ3 -> unit` and the
  name is `set`, then the declaration is assumed to be a
  `[@@js.set_index]` index setter.

- If the value is a function with two arguments `τ1 -> τ2 -> unit` and
  its name starts with `set_`, then the declaration is assumed to be a
  `[@@js.set]` property setter (on the property whose name is obtained
  by dropping the `set_` prefix).

- If the value is a function with a single argument (named type) `τ ->
  unit`, then the declaration is assumed to be a `[@@js.call]` method
  call.

- If the value is a function with two arguments whose first argument is
  a named type `τ -> τ2 -> τ3` (and `τ3` is not `unit`) and the name is
  `get`, then the declaration is assumed to be a `[@@js.index_get]`
  index getter.

- If the value is a function with a single argument (named type) `τ ->
  τ2` (and `τ2` is not `unit`), then the declaration is assumed to be
  a `[@@js.get]` property getter.

- If the value is a function with a single argument `unit -> τ2`, then
  the declaration is assumed to be a `[@@js.get]` global getter.

- If the value is a function whose first argument is a named type `τ
  -> ...` and the name is `apply`, then the definition is assumed to
  be a `[@@js.apply]` function object application.

- If the value is a function whose first argument is a named type `τ
  -> ...` (and the name is not `apply`), then the definition is assumed
  to be a `[@@js.call]` method call.

- Otherwise, the declaration is assumed to be a `[@@js.global]` value.
  This applies in particular for any non-functional type.


================================================
FILE: dune
================================================
(env
 (dev
  (flags (:standard))))

(deprecated_library_name
 (old_public_name gen_js_api)
 (new_public_name ojs))


================================================
FILE: dune-project
================================================
(lang dune 3.17)
(name gen_js_api)
(version 1.1.7)

(maintainers "Alain Frisch <alain.frisch@lexifi.com>")
(authors
 "Alain Frisch <alain.frisch@lexifi.com>"
 "Sebastien Briais <sebastien.briais@lexifi.com>")

(source (github LexiFi/gen_js_api))

(generate_opam_files true)

(license MIT)

(package
 (name ojs)
 (synopsis "Runtime Library for gen_js_api generated libraries")
 (description "To be used in conjunction with gen_js_api")
 (depends
   (ocaml (>= 4.13))
   (js_of_ocaml-compiler (>= 6.3.0)))
 )

(package
 (name gen_js_api)
 (synopsis "Easy OCaml bindings for JavaScript libraries")
 (description "
gen_js_api aims at simplifying the creation of OCaml bindings for
JavaScript libraries.  Authors of bindings write OCaml signatures for
JavaScript libraries and the tool generates the actual binding code
with a combination of implicit conventions and explicit annotations.

gen_js_api is to be used with the js_of_ocaml compiler.
 ")
 (conflicts (js_of_ocaml-compiler (< 6.3.0)))
 (depends
  (ocaml (>= 4.13))
  (ppxlib (>= 0.37))
  (js_of_ocaml-compiler :with-test)
  (ojs (= :version)))
)


================================================
FILE: examples/calc/calc.html
================================================
<html>
  <head>
    <title>Calculator</title>
  </head>
  <body>
    <script src="calc.js"></script>
  </body>
</html>


================================================
FILE: examples/calc/calc.ml
================================================
module Element = [%js:
  type t

  val t_of_js: Ojs.t -> t

  val append_child: t -> t -> unit [@@js.call]

  val set_attribute: t -> string -> string -> unit [@@js.call]

  val set_onclick: t -> (unit -> unit) -> unit [@@js.set]
]

module Window = [%js:
  type t

  val instance: t [@@js.global "window"]

  val set_onload: t -> (unit -> unit) -> unit [@@js.set]
]

module Document = [%js:
  type t

  val instance: t [@@js.global "document"]

  val create_element: t -> string -> Element.t [@@js.call]

  val create_text_node: t -> string -> Element.t [@@js.call]

  val body: t -> Element.t [@@js.get]
]

let element tag children =
  let elt = Document.create_element Document.instance tag in
  List.iter (Element.append_child elt) children;
  elt

let textnode s = Document.create_text_node Document.instance s

let td ?colspan child =
  let elt = element "td" [child] in
  begin match colspan with
  | None -> ()
  | Some n -> Element.set_attribute elt "colspan" (string_of_int n)
  end;
  elt

let tr = element "tr"
let table = element "table"
let center x = element "center" [x]

let button x f =
  let elt = element "button" [textnode x] in
  Element.set_attribute elt "type" "button";
  Element.set_onclick elt f;
  elt

module Engine = struct
  type op = Add | Sub | Mul | Div

  type state =
    {
      x: float;
      y: float;
      operator: op option;
      input: bool;
      equal: bool;
      comma: int;
    }

  let initial = { x = 0.; y = 0.; operator = None; input = false; equal = false; comma = 0 }

  let make_op op x y =
    match op with
    | Add -> x +. y
    | Sub -> x -. y
    | Mul -> x *. y
    | Div -> x /. y

  let of_digit d = float_of_int d
  let add_digit x comma d =
    if comma = 0 then 10. *. x +. float_of_int d, comma
    else x +. float_of_int d /. (10. ** (float_of_int comma)), comma + 1

  let input_digit ({x; y; operator = _; input; equal; comma} as state) d =
    let y = if equal then y else x in
    let x, comma =
      if input then add_digit x comma d
      else of_digit d, 0
    in
    {state with x; y; comma; input = true}

  let apply_comma ({input; comma; _} as state) =
    if comma = 0 then
      if input then {state with comma = 1}
      else {(input_digit state 0) with comma = 1}
    else state

  let apply_equal ({x; y; operator; input; equal; comma = _} as state) =
    match operator with
    | None -> {state with y = x; input = false; equal = true}
    | Some o ->
        if input && not equal then {state with x = make_op o y x; y = x; input = false; equal = true}
        else {state with x = make_op o x y; equal = true}

  let apply_op ({input; equal; _} as state) op =
    if input && not equal then {(apply_equal state) with operator = Some op; equal = false}
    else {state with operator = Some op; equal= false; input = false}

  let print_op ppf = function
    | None -> Printf.fprintf ppf " "
    | Some Add -> Printf.fprintf ppf "+"
    | Some Sub -> Printf.fprintf ppf "-"
    | Some Mul -> Printf.fprintf ppf "*"
    | Some Div -> Printf.fprintf ppf "/"

  let print ppf {x; y; operator; input; equal; comma} =
    Printf.fprintf ppf "x = %g, y = %g, op = %a, input = %b, equal = %b, comma = %d" x y print_op operator input equal comma
end


let widget () =
  let open Engine in
  let state = ref initial in
  let res, set_value =
    let elt = element "input" [] in
    Element.set_attribute elt "type" "text";
    Element.set_attribute elt "readonly" "";
    let set_value v = Element.set_attribute elt "value" (string_of_float v) in
    elt, set_value
  in
  let update st =
    Printf.printf "%a\n" print st;
    state := st;
    set_value !state.x
  in
  let reset() = update initial in
  reset();
  let binop op () = update (apply_op !state op) in
  let equal () = update (apply_equal !state) in
  let comma () = update (apply_comma !state) in
  let figure digit =
    let f () = update (input_digit !state digit) in
    button (string_of_int digit) f
  in
  let c l = td l in
  let nothing () = element "div" [] in
  table [tr [td ~colspan:4 res];
         tr (List.map c [nothing(); button "C" reset; nothing(); button "/" (binop Div)]);
         tr (List.map c [figure 7; figure 8; figure 9; button "*" (binop Mul)]);
         tr (List.map c [figure 4; figure 5; figure 6; button "-" (binop Sub)]);
         tr (List.map c [figure 1; figure 2; figure 3; button "+" (binop Add)]);
         tr (List.map c [nothing(); figure 0; button "." comma; button "=" equal])]

let go () =
  Element.append_child (Document.body Document.instance) (center (widget()))

let () =
  Window.set_onload Window.instance go


================================================
FILE: examples/calc/dune
================================================
(executables
 (names calc)
 (libraries ojs)
 (preprocess
  (pps gen_js_api.ppx))
 (modes js))

(rule
 (targets calc.js)
 (deps calc.bc.js)
 (action
  (run cp %{deps} %{targets})))

(alias
 (name DEFAULT)
 (deps calc.js calc.html))


================================================
FILE: examples/misc/dune
================================================
(executables
 (names test_jquery)
 (libraries ojs)
 (preprocess
  (pps gen_js_api.ppx))
 (modes js))

(rule
 (targets jquery.ml)
 (deps jquery.mli)
 (action
  (run %{bin:gen_js_api} %{deps})))

(rule
 (targets js_date.ml)
 (deps js_date.mli)
 (action
  (run %{bin:gen_js_api} %{deps})))

(rule
 (targets js_str.ml)
 (deps js_str.mli)
 (action
  (run %{bin:gen_js_api} %{deps})))

(rule
 (targets test_jquery.js)
 (deps test_jquery.bc.js)
 (action
  (run cp %{deps} %{targets})))

(alias
 (name DEFAULT)
 (deps test_jquery.js test_jquery.html))


================================================
FILE: examples/misc/jquery.mli
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** Partial binding to jQuery, serving as an illustration
    of gen_js_api.  The binding is far from complete! *)

[@@@js.implem [@@@ocaml.warning "-22"]]

(** {2 Sets of elements} *)

type t = private Ojs.t

val selector: string -> t
  [@@js.global "jQuery"]
(** Either select a set of elements from the current document, or
    create a new element (if given a string such as "<div>". *)

val wrap: Ojs.t -> t [@@js.global "jQuery"]

val explode: t -> t list
    [@@js.custom let explode x = Ojs.list_of_js wrap x]

val find: t -> string -> t list
    [@@js.custom
val find: t -> string -> t [@@js.call "find"]

let find x sel = explode (find x sel)
    ]


val text: t -> string
  [@@js.call]

val set_text: t -> string -> unit
  [@@js.call "text"]

val update_text: t -> (int -> string -> string) -> unit
  [@@js.call "text"]

val append_html: t -> string -> unit
  [@@js.call "append"]

val append: t -> (t list [@js.variadic]) -> unit
  [@@js.call "append"]

val prepend: t -> (t list [@js.variadic]) -> unit
  [@@js.call]

val after: t -> t -> unit
  [@@js.call]

val before: t -> t -> unit
  [@@js.call]

val get_val: t -> string
  [@@js.call "val"]

val hide: t -> unit
  [@@js.call]

val show: t -> unit
  [@@js.call]

val detach: t -> unit
  [@@js.call]

val remove: t -> unit
  [@@js.call]

val empty: t -> unit
  [@@js.call]

val focus: t -> unit

val height: t -> int [@@js.call]
val set_height: t -> ([`String of string | `Int of int] [@js.union]) -> unit [@@js.call "height"]

val width: t -> int [@@js.call]
val set_width: t -> ([`String of string | `Int of int] [@js.union]) -> unit [@@js.call "width"]

val string_value: t -> string [@@js.call "val"]
val set_string_value: t -> string -> unit [@@js.call "val"]

val add_class: t -> string -> unit [@@js.call]
val remove_class: t -> string -> unit [@@js.call]

val css: t -> string -> Ojs.t [@@js.call]

val set_css_value: t -> string -> ([`String of string | `Float of float] [@js.union]) -> unit [@@js.call "css"]

val set_css: t -> Ojs.t -> unit [@@js.call "css"]

val clone: t -> t [@@js.call]

val html: t -> string
  [@@js.call "html"]

val set_html: t -> string -> unit
  [@@js.call "html"]


(** {2 Properties} *)

val prop: t -> string -> Ojs.t
  [@@js.call]

val set_prop:
  t -> string ->
  ([`String of string | `Int of int | `Bool of bool | `Any of Ojs.t] [@js.union]) ->
  unit
  [@@js.call "prop"]

(** {2 Data} *)

val data: t -> string -> Ojs.t
  [@@js.call]

val set_data: t -> string -> Ojs.t -> unit
  [@@js.call "data"]

(** {2 Attributes} *)

val attr: t -> string -> string option
  [@@js.call]

val set_attr: t -> string -> string -> unit
  [@@js.call "attr"]

val remove_attr: t -> string -> unit
  [@@js.call]


(** {2 Animations} *)

val fade_in: t -> ?duration:int -> ?finished:(unit -> unit) -> unit -> unit
  [@@js.call]
val fade_out: t -> ?duration:int -> ?finished:(unit -> unit) -> unit -> unit
  [@@js.call]

(** {2 Events} *)

module Event : sig
  type t

  val page_x: t -> float
  val page_y: t -> float
  val type_: t -> string
  val target: t -> Ojs.t
  val which: t -> int
  val stop_propagation: t -> unit [@@js.call]
  val prevent_default: t -> unit [@@js.call]
end

val on: t -> string -> (Event.t -> unit) -> unit
val off: t -> string -> unit

val trigger: t -> string -> unit
  [@@js.call]

val ready: (unit -> unit) -> unit
  [@@js.global "jQuery"]

module Dialog: sig
  type button

  val button:
    text:string ->
    click:(unit -> unit) ->
    unit -> button
    [@@js.builder]

  type settings

  val settings:
    ?modal:bool ->
    ?title:string ->
    ?buttons:button list ->
    unit -> settings
    [@@js.builder]
end

module UI : sig

  module Datepicker : sig
    type settings

    val settings:
      ?date_format:string ->
      unit -> settings
      [@@js.builder]
  end

  val datepicker: t -> Datepicker.settings -> unit
end

val dialog: t -> ([`Dialog of Dialog.settings | `String of string] [@js.union]) -> unit

(** {2 AJAX} *)

module Ajax: sig
  type settings
  (** The type describing all settings of an AJAX call. *)

  type t
  (** Corresponds to jQuery's jqXHR object. *)

  val settings:
    ?async:bool ->
    ?cache:bool ->
    ?complete:(t -> string -> unit) ->
    ?error:(t -> string -> string -> unit) ->
    ?success:(Ojs.t -> string -> t -> unit) ->
    ?data:Ojs.t -> ?data_type:string ->
    ?meth:([`GET | `POST | `PUT] [@js "method"] [@js.enum]) ->
    ?content_type:string ->
    ?url:string ->
    unit -> settings
      [@@js.builder]

  val run: settings -> unit
      [@@js.global "jQuery.ajax"]

  val response_text: t -> string

  val status: t -> int
end


================================================
FILE: examples/misc/js_date.mli
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** JS dates *)

(** {2 Type definitions} *)

type t = private Ojs.t
val t_of_js: Ojs.t -> t
val t_to_js: t -> Ojs.t

val now: unit -> t [@@js.new "Date"]
val from_milliseconds: float -> t [@@js.new "Date"]
val from_string: string -> t [@@js.new "Date"]

val create: year:int -> month:int -> ?day:(int [@js.default 1]) -> ?hours:(int [@js.default 0]) -> ?minutes:(int [@js.default 0]) -> ?seconds:(int [@js.default 0]) -> ?ms:(int [@js.default 0]) -> unit -> t [@@js.new "Date"]

val get_UTC_date: t -> int [@@js.call]
val get_UTC_day: t -> int [@@js.call]
val get_UTC_full_year: t -> int [@@js.call]
val get_UTC_hours: t -> int [@@js.call]
val get_UTC_milliseconds: t -> int [@@js.call]
val get_UTC_minutes: t -> int [@@js.call]
val get_UTC_month: t -> int [@@js.call]
val get_UTC_seconds: t -> int [@@js.call]

val set_UTC_date: t -> int -> unit [@@js.call]
val set_UTC_full_year: t -> int -> unit [@@js.call]
val set_UTC_hours: t -> int -> unit [@@js.call]
val set_UTC_milliseconds: t -> int -> unit [@@js.call]
val set_UTC_minutes: t -> int -> unit [@@js.call]
val set_UTC_month: t -> int -> unit [@@js.call]
val set_UTC_seconds: t -> int -> unit [@@js.call]

val get_date: t -> int [@@js.call]
val get_day: t -> int [@@js.call]
val get_full_year: t -> int [@@js.call]
val get_hours: t -> int [@@js.call]
val get_milliseconds: t -> int [@@js.call]
val get_minutes: t -> int [@@js.call]
val get_month: t -> int [@@js.call]
val get_seconds: t -> int [@@js.call]

val set_date: t -> int -> unit [@@js.call]
val set_full_year: t -> int -> unit [@@js.call]
val set_hours: t -> int -> unit [@@js.call]
val set_milliseconds: t -> int -> unit [@@js.call]
val set_minutes: t -> int -> unit [@@js.call]
val set_month: t -> int -> unit [@@js.call]
val set_seconds: t -> int -> unit [@@js.call]

val get_time: t -> float [@@js.call]
val set_time: t -> float -> unit [@@js.call]

val get_timezone_offset: t -> int [@@js.call]

val to_locale_date_string: t -> string [@@js.call]
val to_locale_string: t -> string [@@js.call]
val to_locale_time_string: t -> string [@@js.call]

val to_date_string: t -> string [@@js.call]
val to_time_string: t -> string [@@js.call]

val to_UTC_string: t -> string [@@js.call]

val to_string: t -> string [@@js.call]


================================================
FILE: examples/misc/js_str.mli
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** JS string and regexp objects *)

(** {2 Type definitions} *)

type t = private Ojs.t
val t_of_js: Ojs.t -> t
val t_to_js: t -> Ojs.t

type regexp = private Ojs.t
val regexp_of_js: Ojs.t -> regexp
val regexp_to_js: regexp -> Ojs.t

(** {2 Conversion between JS strings and OCaml string} *)

val to_string: t -> string [@@js.cast]
val of_string: string -> t [@@js.cast]

(** {2 JS strings} *)

val from_char_code: (int list [@js.variadic]) -> t
    [@@js.global "String.fromCharCode"]

val char_at: t -> int -> t
val char_code_at: t -> int -> int
val concat: t -> (t list [@js.variadic]) -> t
val index_of: t -> t -> ?start:int -> unit -> int
val last_index_of: t -> t -> ?start:int -> unit -> int
val length: t -> int
val locale_compare: t -> t -> int
val match_: t -> regexp -> t array option
val replace: t -> regexp -> t -> t
val search: t -> regexp -> int
val slice: t -> start:int -> ?end_:int -> unit -> t
val split: t -> ?separator:t -> ?limit:int -> unit -> t array
val substr: t -> start:int -> ?length:int -> unit -> t
val substring: t -> start:int -> ?end_:int -> unit -> t
val to_locale_lower_case: t -> t [@@js.call]
val to_locale_upper_case: t -> t [@@js.call]
val to_lower_case: t -> t [@@js.call]
val to_upper_case: t -> t [@@js.call]
val trim: t -> t [@@js.call]


(** {2 Regexps} *)

val regexp: t -> ?global:unit -> ?ignore_case:unit -> ?multiline:unit -> unit -> regexp
 [@@js.custom

      val regexp_internal: t -> ?flags:t -> unit -> regexp [@@js.new "RegExp"]

      let regexp txt ?global ?ignore_case ?multiline () =
        let l = [] in
        let l = match global with Some () -> of_string "g" :: l | None -> l in
        let l = match ignore_case with Some () -> of_string "i" :: l | None -> l in
        let l = match multiline with Some () -> of_string "m" :: l | None -> l in
        regexp_internal txt ~flags:(concat (of_string "") l) ()
 ]


val global: regexp -> bool
val ignore_case: regexp -> bool
val multiline: regexp -> bool
val source: regexp -> string
val last_index: regexp -> int
val exec: regexp -> t -> t array option
val test: regexp -> t -> bool


================================================
FILE: examples/misc/test_jquery.html
================================================
<html>
  <head>
  </head>
  <body>
    <span class="tofill">One</span>
    <span class="tofill">Two</span>
    <div id="main">Blabla</div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script type="text/javascript" src="test_jquery.js">
    </script>
  </body>
</html>


================================================
FILE: examples/misc/test_jquery.ml
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** A toy application built with jQuery *)

open Jquery

include [%js:
val alert: string -> unit
  [@@js.global]
]

let ( !! ) = Jquery.selector

let block s ?text ?(classes = []) ?(ons = []) ?(css = []) ?(props = []) children =
  let element = Jquery.selector (Printf.sprintf "<%s>" s) in
  begin match text with
  | None -> ()
  | Some text -> Jquery.set_text element text
  end;
  List.iter (fun c -> Jquery.add_class element c) classes;
  List.iter (fun (key, value) -> Jquery.set_css_value element key value) css;
  List.iter (fun (key, value) -> Jquery.set_prop element key value) props;
  List.iter (fun (event, f) -> Jquery.on element event f) ons;
  begin match children with
    | [] -> ()
    | _ :: _-> Jquery.append element children
  end;
  element

let ajax_test () =
  let open Ajax in
  let complete h = function
    | "success" ->
        let pre = block "pre" ~text:(response_text h) [] in
        hide pre;
        append !!"body" [pre];
        fade_in pre ~duration:2000
          ~finished:(fun () ->
              fade_out pre ~finished:(fun () -> detach pre) ()
            )
          ()
    | status -> alert (Printf.sprintf "status = %s" status)
  in
  run (settings ~meth:`GET ~url:"test_jquery.ml" ~data_type:"text" ~complete ())


let on_ready () =
  let main = !!"#main" in
  print_endline (text main);
  set_text main "Hello world!";
  append_html main "<b>in bold</b>";

  let elts = !!".tofill" in
  update_text elts (Printf.sprintf "[%i:%s]");

  append main [elts; !! "<b>XXX</b>"];

  let on_click evt =
    let open Event in
    append_html main
      (Printf.sprintf "<br/>x=%f,y=%f,type=%s"
         (page_x evt)
         (page_y evt)
         (type_ evt)
      )
  in
  on main "click" on_click;

  let div = block "div" [] in
  let input = block "input" [] in
  on input "input" (fun _ -> set_text div (get_val input));
  append main [input; div];

  let btn =
    block "button" ~text:"SHOW SOURCE CODE" []
      ~ons:["click", (fun _ -> ajax_test ())]
  in
  append main [btn]

let () =
  ready on_ready


================================================
FILE: examples/test/dune
================================================
(executables
 (names main)
 (libraries ojs)
 (preprocess
  (pps gen_js_api.ppx))
 (modes js))

(rule
 (targets test_bindings.ml)
 (deps test_bindings.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (targets main.js)
 (deps main.bc.js)
 (action
  (run cp %{deps} %{targets})))

(alias
 (name DEFAULT)
 (deps main.js main.html))


================================================
FILE: examples/test/main.html
================================================
<html>
  <head>
  </head>
  <body>
    <div class="myClass">Blabla</div>
    <canvas id="canvas" width="200" height="200">
      Bla
    </canvas>
    <script type="text/javascript">
      var myArray = [1, 2, 3];

      function wrapper(f) {
          return function (x, y) {
              console.log("Before");
              var r = f(x, y);
              console.log("Result 1 = " + r);
              var r = f(r, y);
              console.log("Result 2 = " + r);
              return r;
          }
      }
      function caller(f) {
        console.log("Before call");
        var r = f();
        console.log("After call");
        return r;
      }

      function Person(name, foo) {
        console.log(arguments);
        this.name = name;
        this.foo = foo;
        this.get = function () {
          return [this.name, this.foo];
        };
        this.set = function (a) {
          this.name = a[0];
          this.foo = a[1];
        };
        console.log("New Person object created");
      }

      function testVariadic(f) {
        console.log(f());
        console.log(f(0));
        console.log(f(0, 1));
        console.log(f(0, 1, 2));
        console.log(f(0, 1, 2, 3));
        console.log(f(0, 1, 2, 3, 4));
      }

      function testVariadic2(f) {
        console.log(f("Hello"));
        console.log(f("Hello", 0));
        console.log(f("Hello", 0, 1));
        console.log(f("Hello", 0, 1, 2));
        console.log(f("Hello", 0, 1, 2, 3));
        console.log(f("Hello", 0, 1, 2, 3, 4));
      }

      function testOptArgs(f) {
        console.log(f());
        console.log(f(10));
        console.log(f(10, 10));
      }

      function test_sum() {
        print_sum({kind:"A"});
        print_sum({kind:"B", arg:806});
        print_sum({kind:"C", arg:[806, "bar"]});
        print_sum({kind:"D", age:24, name:"Toto"});
      }

      var myDict = { "gen_js_api": "OK", "js_of_ocaml": "OK" };

      function test_flatten(kind) {
        switch(kind) {
        case "A": {
          console.log("A");
          break;
        }
        case "B": {
          console.log("B "+arguments[1]);
          break;
        }
        case "C": {
          console.log("C "+arguments[1]);
          break;
        }
        case "D": {
          console.log("D ("+arguments[1]+", "+arguments[2]+")");
          break;
        }
        }
      }

      function test_typvars(anything) {
        return [anything, anything]
      }

      function makeRef(anything) {
        return {current: anything}
      }

      function eitherLeft(anything) {
        return {left: anything};
      }
      function eitherRight(anything) {
        return {right: anything};
      }
      function eitherDestruct(x, left, right) {
        if (x.hasOwnProperty("left")) {
          return left(x.left);
        } else {
          return right(x.right);
        }
      }
    </script>
    <script type="text/javascript" src="main.js">
    </script>
    <script type="text/javascript">
      console.log(myArray);
    </script>
  </body>
</html>


================================================
FILE: examples/test/main.ml
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** Some ad hoc code to illustrate and test various aspects
    of gen_js_api *)

[@@@ocaml.warning "-32-34"]

open Test_bindings

[@@@ocaml.warning "-22"]

include
  [%js:
    val wrapper: (int -> int -> int) -> (int -> int -> int [@js.dummy])
    [@@js.global "wrapper"]

    val caller: (unit -> int) -> int
    [@@js.global "caller"]

    val caller_unit: (unit -> unit) -> unit
    [@@js.global "caller"]

    val test_variadic: ((int list [@js.variadic]) -> int) -> unit
    val test_variadic2: (string -> (int list [@js.variadic]) -> int) -> unit
  ]

module LocalBindings = [%js:
  type myType = { x : a; y : b [@js "Y"]}
  and a = int option
  and b = { s : string; i : int }
]


let () =
  let s = [%js.of: int list] [10; 20; 30] in
  Printf.printf "%i\n%!" ([%js.to: int] (Ojs.array_get s 0));
  Printf.printf "%i\n%!" ([%js.to: int] (Ojs.array_get s 1));
  Printf.printf "%i\n%!" ([%js.to: int] (Ojs.array_get s 2))

let () =
  let sum xs = List.fold_left ( + ) 0 xs in
  test_variadic sum;
  test_variadic2 (fun msg xs -> Printf.printf "%s\n%!" msg; sum xs)

include [%js:
val myArray: int array
    [@@js]

val myArray2: Ojs.t
    [@@js.global "myArray"]

val alert_bool: bool -> unit
    [@@js.global "alert"]

val alert_float: float -> unit
    [@@js.global "alert"]


val test_opt_args: (?foo:int -> ?bar:int -> unit-> string) -> unit
  [@@js.global]
]

let doc = Window.document window

let elt name ?(attrs = []) ?onclick subs =
  let e = Document.createElement doc name in
  List.iter (fun (k, v) -> Element.setAttribute e k v) attrs;
  List.iter (Element.appendChild e) subs;
  begin match onclick with
  | Some f -> Element.set_onclick e f
  | None -> ()
  end;
  e

let txt =
  Document.createTextNode doc

let button ?attrs s onclick =
  elt "button" ?attrs ~onclick [ txt s ]

let div = elt "div"

let () =
  Array.iter (Printf.printf "[%i]\n") myArray;

  Ojs.array_set myArray2 0 (Ojs.int_to_js 10);
  Ojs.array_set myArray2 1 (Ojs.array_to_js Ojs.int_to_js [| 100; 200; 300 |]);
(*  Ojs.array_set myArray2 1 ([%to_js: int array] [| 100; 200; 300 |]); *)

(*
  Printf.printf "%0.2f\n" 3.1415;
*)
(*
  Document.set_title doc "MyTitle";
  Document.set_title doc (Document.title doc ^ " :-)");
*)

(*  let main = Document.getElementById doc "main" in *)
(*  print_endline (Element.innerHTML main); *)
(*  alert (Element.innerHTML main); *)
(*  Element.set_innerHTML main "<b>Bla</b>blabla"; *)


  let draw () =
    let canvas_elt = Document.getElementById doc "canvas" in
    let canvas = Canvas.of_element canvas_elt in
    let ctx = Canvas.getContext_2d canvas in
    Canvas.RenderingContext2D.(begin
        set_fillStyle ctx "rgba(0,0,255,0.1)";
        fillRect ctx 30 30 50 50
      end);
    Element.set_onclick canvas_elt (fun () -> alert "XXX");
  in
  alert_bool true;
  alert_float 3.1415;
  let f =
    wrapper
      (fun x y ->
         Printf.printf "IN CALLBACK, x = %i, y = %i\n%!" x y;
         x + y
      )
  in
  Printf.printf "Result -> %i\n%!" (f 42 1);

  let uid = ref 0 in
  let f () =
    incr uid;
    Printf.printf "uid = %i\n%!" !uid;
    !uid
  in
  Printf.printf "Caller result -> %i, %i, %i\n%!" (caller f) (caller f) (caller f);
  caller_unit (fun () -> ignore (f ()));
  caller_unit (fun () -> ignore (f ()));
  caller_unit (fun () -> ignore (f ()));

  let alice = Person.create "Alice" Person.Foo.Foo in
  let bob = Person.create "Bob" Person.Foo.Bar in
  let charlie = Person.create "Charlie" (Person.Foo.OtherString "bla") in
  let eve = Person.create "Eve" (Person.Foo.OtherInt 2713) in

  Ojs.iter_properties (Person.cast alice) (Format.printf "%s\n%!");

  let alice_obj = PersonObj.create "Alice" Person.Foo.Foo in
  let bob_obj = PersonObj.of_person bob in
  let dave_obj = new PersonObj.person "Dave" Person.Foo.Bar [1; 2; 3] in

  let string_of_foo = function
    | Person.Foo.Foo -> "foo"
    | Person.Foo.Bar -> "bar"
    | Person.Foo.OtherInt n -> Printf.sprintf "other = %d" n
    | Person.Foo.OtherString s -> Printf.sprintf "other = %s" s
  in
  let string_of_name_foo name foo = Printf.sprintf "%s <%s>" name (string_of_foo foo) in
  let string_of_person x = string_of_name_foo (Person.name x) (Person.foo x) in
  let string_of_person_obj x = string_of_name_foo (x # name) (x # foo) in
  let hack_person x =
    let name, foo = Person.get x () in
    Printf.printf "before: %s <%s>\n" name (string_of_foo foo);
    Person.set x ("Dave", Person.Foo.OtherString "bar");
    let name, foo = Person.get x () in
    Printf.printf "after: %s <%s>\n" name (string_of_foo foo);
  in

  let body = Document.body doc in
  setTimeout (fun () -> Element.setAttribute body "bgcolor" "red") 2000;
  Element.appendChild body (Document.createTextNode doc "ABC");
  Element.appendChild body
    (div ~attrs:["style", "color: blue"] [ txt "!!!!"; elt "b" [txt "XXX"]]);

  Element.appendChild body
    (div (List.map (fun x -> txt (string_of_person x)) [alice; bob; charlie; eve]));
  hack_person eve;
  Element.appendChild body
    (div (List.map (fun x -> txt (string_of_person x)) [alice; bob; charlie; eve]));
  Element.appendChild body
    (div (List.map (fun x -> txt (string_of_person_obj x)) [alice_obj; bob_obj; dave_obj]));

  let s = (new Str.str "") # concat [Str.create "Hello"; Str.create ", "; Str.create "world"; Str.create "!"] in
  Console.log_string console (s # to_string);

  Console.log_string console (Date.to_string (Date.create ~year:2015 ~month:4 ~day:10 ()));

  let l = Document.getElementsByClassName doc "myClass" in
  Array.iter
    (fun e ->
       Printf.printf "- [%s]\n" (Element.innerHTML e); (* OK *)
       print_string (Printf.sprintf "+ [%s]\n" (Element.innerHTML e)); (* BAD *)

       Element.appendChild e (button "Click!" draw);
       Element.appendChild e (button "XXX" (fun () -> ()));
    )
    l;

  test_opt_args
    (fun ?(foo = 0) ?(bar = 0) () -> string_of_int foo ^ "/" ^ string_of_int bar);

  print_endline Person2.(to_json (mk ~children:[mk ~age:6 "Johnny"] ~age:42 "John Doe"))



(* Custom mapping between association lists and JS objects *)

module Dict : sig
  type 'a t = (string * 'a) list
  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
end = struct
  type 'a t = (string * 'a) list

  let t_to_js ml2js l =
    let o = Ojs.empty_obj () in
    List.iter (fun (k, v) -> Ojs.set_prop o (Ojs.string_to_js k) (ml2js v)) l;
    o

  let t_of_js js2ml o =
    let l = ref [] in
    Ojs.iter_properties o
      (fun k -> l := (k, js2ml (Ojs.get_prop o (Ojs.string_to_js k))) :: !l);
    !l
end

include [%js:
val int_dict_to_json_string: int Dict.t -> string
  [@@js.global "JSON.stringify"]

val myDict: string Dict.t
  [@@js.global "myDict"]

val set_x: int -> unit
    [@@js.set "x"]

val get_x: unit -> int
    [@@js.get "x"]
]

let () =
  print_endline (int_dict_to_json_string ["hello", 1; "world", 2]);
  List.iter (fun (k, v) -> Printf.printf "%s -> %s\n%!" k v) myDict;
  set_x 42;
  print_endline (string_of_int (get_x ()))

module Sum = struct
  include [%js:
    type t =
      | A
      | B of int
      | C of int * string
      | D of {age:int; name:string}
    [@@js.sum]

    val t_of_js: Ojs.t -> t
    val t_to_js: t -> Ojs.t
  ]

let print = function
  | A -> print_endline "A"
  | B n -> print_endline (Format.sprintf "B %d" n)
  | C (n, s) -> print_endline (Format.sprintf "C (%d, %S)" n s)
  | D {age; name} -> print_endline (Format.sprintf "D {age = %d; name = %S}" age name)

include [%js:
val set_print_sum: (t -> unit) -> unit
    [@@js.set "print_sum"]

val test_sum: unit -> unit
    [@@js.global "test_sum"]
]

let () =
  set_print_sum print

let () = test_sum ()

let () =
  Console.log console ([%js.of:t] A);
  Console.log console ([%js.of:t] (B 42));
  Console.log console ([%js.of:t] (C (42, "foo")));
  Console.log console ([%js.of:t] (D {age=42; name="foo"}))

let () =
  Console3.log 1;
  Console3.log2 1 "two";
  Console3.log3 1 "two" [];
  Console3.log4 1 "two" [] [|4|]

let () =
  Console4.log  (module Ojs.Int) 1;
  Console4.log2 (module Ojs.Int) (module Ojs.String) 1 "two";
  Console4.log3 (module Ojs.Int) (module Ojs.String) (module Ojs.List(Ojs.Int)) 1 "two" [3]

end

include [%js:
val test_flatten: ([`A | `B of int | `C of string | `D of int * string] [@js.enum]) -> unit
    [@@js.global "test_flatten"]
]

let () =
  test_flatten `A;
  test_flatten (`B 42);
  test_flatten (`C "hello");
  test_flatten (`D (42, "foo"))
include [%js:
val make_string : 'a -> string [@@js.global "String"]
]

let () =
  Console3.log (make_string 1234);
  Console3.log (make_string "string");
  Console3.log (make_string ["list"]);
  Console3.log (make_string [|"array"|])

include [%js:
val test_typvars: 'a -> 'a * 'a
    [@@js.global "test_typvars"]
]

let () =
  Console3.log (test_typvars `A);
  Console3.log (test_typvars 1234);
  Console3.log (test_typvars "string");
  Console3.log (test_typvars ["list"])

let () =
  let t = Ref.make "foo" in
  Console3.log (Ref.current t);
  Ref.setCurrent t "bar";
  Console3.log (Ref.current t)

let () =
  let foo = Either.left "foo" in
  let foobar = Either.right ["foo"; "bar"] in
  let f x = Either.destruct x ~left:(fun s -> s) ~right:(String.concat "-") in
  Console3.log (Ojs.string_to_js (f foo));
  Console3.log (Ojs.string_to_js (f foobar))

let () =
  let open Variants.M3 in
  let rec of_list = function
  | [] -> Empty
  | hd :: tl -> Cons (hd, of_list tl)
  in
  Console3.log ([%js.of: int t] (of_list [1;2;3]))


================================================
FILE: examples/test/test_bindings.mli
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** Some ad hoc code to illustrate and test various aspects
    of gen_js_api *)

[@@@js.implem [@@@ocaml.warning "-22"]]

module Element : sig
  type t = private Ojs.t

  val appendChild: t -> t -> unit
  val set_innerHTML: t -> string -> unit
  val innerHTML: t -> string

  val set_onclick: t -> (unit -> unit) -> unit
  val setAttribute: t -> string -> string -> unit
end

module Canvas : sig
  module RenderingContext2D : sig
    type t = private Ojs.t

    val set_fillStyle: t -> string -> unit
    val fillRect: t -> int -> int -> int -> int -> unit
  end

  type t = private Ojs.t

  val of_element: Element.t -> t
      [@@js.cast]

  val getContext_2d: t -> RenderingContext2D.t
      [@@js.custom
          val get_context: t -> string -> Ojs.t
          [@@js.call]

          let getContext_2d x =
            get_context x "2d"
      ]
end


module Document : sig
  type t = private Ojs.t

  val set_title: t -> string -> unit
  val title: t -> string

  val getElementById: t -> string -> Element.t
  val getElementsByClassName: t -> string -> Element.t array

  val createElement: t -> string -> Element.t
  val createTextNode: t -> string -> Element.t

  val body: t -> Element.t
end

module Window : sig
  type t = private Ojs.t

  val t_of_js: Ojs.t -> t
  val t_to_js: t -> Ojs.t

  val document: t -> Document.t

  val set_onload: t -> (unit -> unit) -> unit
end

val window: Window.t

val alert: string -> unit
  [@@js.global]

val setTimeout: (unit -> unit) -> int -> unit

module Console: sig
  type t = private Ojs.t

  val log: t -> Ojs.t -> unit

  val log_string: t -> string -> unit
  [@@js.call "log"]
end

val console: Console.t

module Person: sig
  module Foo: sig
    type t =
      | Foo
      | Bar [@js 42]
      | OtherInt of int [@js.default]
      | OtherString of string [@js.default]
            [@@js.enum]
  end

  type t = private Ojs.t

  val create: string -> Foo.t -> t
  [@@js.new "Person"]

  val name: t -> string
  val foo: t -> Foo.t
  val get: t -> unit -> string * Foo.t
  [@@js.call]
  val set: t -> string * Foo.t -> unit
      [@@js.call]

  val cast: t -> Ojs.t [@@js.cast]
end

module PersonObj: sig
  class t: Ojs.t ->
     object
       inherit Ojs.obj
       method name: string
       method set_name: string -> unit
       method foo: Person.Foo.t
       method set_foo: Person.Foo.t -> unit
       method get: string * Person.Foo.t [@@js.call]
       method set: string * Person.Foo.t -> unit [@@js.call]
     end

  class person: string -> Person.Foo.t -> (int list [@js.variadic]) -> t

  val create: string -> Person.Foo.t -> t
  [@@js.new "Person"]

  val of_person: Person.t -> t
  [@@js.cast]
end

module Str: sig
  class t: Ojs.t ->
    object
      inherit Ojs.obj
      method concat: (t list [@js.variadic]) -> t
      method to_string: string [@@js.call]
    end

  class str: string -> t [@@js.new "String"]

  val create: string -> t
  [@@js.new "String"]
end

module Date: sig
  type t = private Ojs.t

  val create: year:int -> month:int -> ?day:(int[@js.default 0]) -> unit -> t [@@js.new "Date"]
  val to_string: t -> string [@@js.call]
end

module Person2: sig
  type t = private Ojs.t

  val mk: ?children:t list -> age:int -> (string[@js "name"]) -> t
  [@@js.builder]

  val to_json:  t -> string
  [@@js.global "JSON.stringify"]
end

type int_or_string_or_null =
  | Int of int
  | String of string
  | Nothing
    [@@js.union]

val f: ([`Int of int | `String of string | `Nothing] [@js.union]) -> unit

val g: int_or_string_or_null -> unit [@@js.global]

module Verb1: sig
  type t1 =
    { x_coord: int;
      y_coord: int;
    }

  class t2: Ojs.t ->
    object
      inherit Ojs.obj
      method x_coord: int
      method y_coord: int
    end
end [@js.verbatim_names]

module Verb2: sig
  type t1 =
    { x_coord: int;
      y_coord: int;
    } [@@js.verbatim_names]

  class t2: Ojs.t ->
    object
      inherit Ojs.obj
      method x_coord: int
      method y_coord: int
    end [@@js.verbatim_names]
end

module Console2: sig
  val log: string -> unit
    [@@js.global]
end [@js.scope "console"]

module Console3: sig
  val log: 'a -> unit [@@js.global "console.log"]
  val log2: 'a -> 'b -> unit [@@js.global "console.log"]
  val log3: 'a -> 'b -> 'c -> unit [@@js.global "console.log"]
  val log4: 'a -> 'b -> 'c -> 'd -> unit [@@js.global "console.log"]
end

module Console4: sig
  val log: (module[@js] Ojs.T with type t = 'a) -> 'a -> unit [@@js.global "console.log"]
  val log2:
    (module[@js] Ojs.T with type t = 'a) ->
    (module[@js] Ojs.T with type t = 'b) ->
    'a -> 'b -> unit [@@js.global "console.log"]
  val log3:
    (module[@js] Ojs.T with type t = 'a) ->
    (module[@js] Ojs.T with type t = 'b) ->
    (module[@js] Ojs.T with type t = 'c) ->
    'a -> 'b -> 'c -> unit [@@js.global "console.log"]
end

module Location: sig
  val hash: unit -> string
  val set_hash: string -> unit
end [@js.scope "location"]

module Location2: sig
  val hash: unit -> string [@@js.get]
  val set_hash: string -> unit [@@js.set]
end [@js.scope "location"]

module Location3: sig
  val assign: string -> unit
  val reload: ?force:bool -> unit -> unit
  val replace: string -> unit
end [@js.scope "location"]

module Union: sig
  type close_path

  type moveto_abs

  type svg_path_seg =
    | Unknown of Ojs.t         [@js.default]
    | Close_path of close_path [@js 1]
    | Moveto_abs of moveto_abs [@js 2]
          [@@js.union on_field "pathSegType"]
end

module Ref : sig
  type 'value t = private Ojs.t
  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t

  val make: 'value -> 'value t [@@js.global "makeRef"]

  val current : 'value t -> 'value [@@js.get "current"]

  val setCurrent : 'value t -> 'value -> unit [@@js.set "current"]
end

module Either : sig
  type ('a, 'b) t
  val t_to_js: ('a -> Ojs.t) -> ('b -> Ojs.t) -> ('a, 'b) t -> Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> (Ojs.t -> 'b) -> Ojs.t -> ('a, 'b) t

  val left: 'a -> ('a, 'b) t [@@js.global "eitherLeft"]
  val right: 'b -> ('a, 'b) t [@@js.global "eitherRight"]
  val destruct: ('a, 'b) t -> left:('a -> 'c) -> right:('b -> 'c) -> 'c [@@js.global "eitherDestruct"]
end

module Alias : sig
  module Swap : sig
    type ('a, 'b) t = ('b, 'a) Either.t
    val t_to_js: ('a -> Ojs.t) -> ('b -> Ojs.t) -> ('a, 'b) t -> Ojs.t
    val t_of_js: (Ojs.t -> 'a) -> (Ojs.t -> 'b) -> Ojs.t -> ('a, 'b) t
  end

  (* Error: Contravariant type parameter !
  module E : sig
    type 'a t = 'a -> int
  end *)

  module Id : sig
    type 'a t = 'a
    val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
    val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
  end

  module Arrow : sig
    type 'a t = ('a -> int) -> string
    val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
    val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
  end

  module Record : sig
    type ('a, 'b) t =
      {
        x: 'a;
        y: 'b
      }
    val t_to_js: ('a -> Ojs.t) -> ('b -> Ojs.t) -> ('a, 'b) t -> Ojs.t
    val t_of_js: (Ojs.t -> 'a) -> (Ojs.t -> 'b) -> Ojs.t -> ('a, 'b) t
  end

end

module Variants : sig

  module M1 : sig
    type 'a t =
      | X of 'a
      | Y of int
      [@@js.sum]
  end

  module M2 : sig
    type ('a, 'b) t =
      | X of 'a
      | Y of 'b
      [@@js.sum]
  end

  module M3 : sig
    type 'a t =
      | Empty
      | Cons of 'a * 'a t
      [@@js.sum]

    val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
    val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
  end

(* Error: Contravariant type parameter !
  module E : sig
    type 'a t =
      | F of ('a -> int)
      [@@js.sum]
  end
*)
  module M4 : sig
    type 'a t =
      | F of (('a -> int) -> int)
      [@@js.sum]
  end

end


================================================
FILE: gen_js_api.opam
================================================
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "1.1.7"
synopsis: "Easy OCaml bindings for JavaScript libraries"
description: """

gen_js_api aims at simplifying the creation of OCaml bindings for
JavaScript libraries.  Authors of bindings write OCaml signatures for
JavaScript libraries and the tool generates the actual binding code
with a combination of implicit conventions and explicit annotations.

gen_js_api is to be used with the js_of_ocaml compiler.
 """
maintainer: ["Alain Frisch <alain.frisch@lexifi.com>"]
authors: [
  "Alain Frisch <alain.frisch@lexifi.com>"
  "Sebastien Briais <sebastien.briais@lexifi.com>"
]
license: "MIT"
homepage: "https://github.com/LexiFi/gen_js_api"
bug-reports: "https://github.com/LexiFi/gen_js_api/issues"
depends: [
  "dune" {>= "3.17"}
  "ocaml" {>= "4.13"}
  "ppxlib" {>= "0.37"}
  "js_of_ocaml-compiler" {with-test}
  "ojs" {= version}
  "odoc" {with-doc}
]
conflicts: [
  "js_of_ocaml-compiler" {< "6.3.0"}
]
build: [
  ["dune" "subst"] {dev}
  [
    "dune"
    "build"
    "-p"
    name
    "-j"
    jobs
    "@install"
    "@runtest" {with-test}
    "@doc" {with-doc}
  ]
]
dev-repo: "git+https://github.com/LexiFi/gen_js_api.git"


================================================
FILE: lib/dune
================================================
(library
 (public_name ojs)
 (synopsis "Runtime support for gen_js_api")
 (libraries js_of_ocaml-compiler.runtime)
 (wrapped false)
 (foreign_stubs
  (language c)
  (names ojs_runtime_stubs))
 (modes byte)
 (js_of_ocaml
  (javascript_files ojs_runtime.js)))


================================================
FILE: lib/ojs.ml
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(* This module (mostly) abstracts away from js_of_ocaml encoding of
   OCaml values.  It serves as a support library for the code generated
   by gen_js_api.

   The module could mostly be implemented on top of js_of_ocaml's Js module
   (and in particular Js.Unsafe), but we prefer to drop the dependency
   to js_of_ocaml's library and to rely only on its compiler and JS
   runtime code.
*)


type t

external t_of_js: t -> t = "%identity"
external t_to_js: t -> t = "%identity"

external string_of_js: t -> string = "caml_js_to_string"
external string_to_js: string -> t = "caml_js_from_string"

external int_of_js: t -> int = "%identity"
external int_to_js: int -> t = "%identity"

external bool_of_js: t -> bool = "caml_js_to_bool"
external bool_to_js: bool -> t = "caml_js_from_bool"

external float_of_js: t -> float = "caml_js_to_float"
external float_to_js: float -> t = "caml_js_from_float"

external obj: (string * t) array -> t = "caml_js_object"

external variable: string -> t = "caml_js_var"

external get: t -> string -> t = "caml_js_get"
external set: t -> string -> t -> unit = "caml_js_set"
external delete: t -> string -> unit = "caml_js_delete"

external get_prop: t -> t -> t = "caml_js_get"
external set_prop: t -> t -> t -> unit = "caml_js_set"
external delete_prop: t -> t -> unit = "caml_js_delete"

external get_prop_ascii: t -> string -> t = "caml_js_get"
external set_prop_ascii: t -> string -> t -> unit = "caml_js_set"
external delete_prop_ascii: t -> string -> unit = "caml_js_delete"

external internal_type_of: t -> t = "caml_js_typeof"
let type_of x = string_of_js (internal_type_of x)

external internal_instance_of: t -> t -> t = "caml_js_instanceof"
let instance_of x ~constr = bool_of_js (internal_instance_of x constr)

external pure_js_expr: string -> t = "caml_pure_js_expr"
let null = pure_js_expr "null"
let undefined = pure_js_expr "undefined"

external equals: t -> t -> bool = "caml_js_equals"

let global = pure_js_expr "globalThis"

external new_obj: t -> t array -> t = "caml_js_new"

external call: t -> string -> t array -> t = "caml_js_meth_call"
external apply: t -> t array -> t = "caml_js_fun_call"

let array_make n = new_obj (get_prop_ascii global "Array") [|int_to_js n|]
let array_get t i = get_prop t (int_to_js i)
let array_set t i x = set_prop t (int_to_js i) x

let array_of_js_from f objs start =
  let n = int_of_js (get_prop_ascii objs "length") in
  Array.init (n - start) (fun i -> f (array_get objs (start + i)))

let array_of_js f objs = array_of_js_from f objs 0

let array_to_js f arr =
  let n = Array.length arr in
  let a = array_make n in
  for i = 0 to n - 1 do
    array_set a i (f arr.(i))
  done;
  a

let list_of_js_from f objs start = Array.to_list (array_of_js_from f objs start)

let list_of_js f objs = list_of_js_from f objs 0

let list_to_js f l =
  array_to_js f (Array.of_list l)

let option_of_js f x =
  if equals x null then None
  else Some (f x)

let option_to_js f = function
  | Some x -> f x
  | None -> null

let unit_to_js () = undefined
let unit_of_js _ = ()

class obj (x:t) =
  object
    method to_js = x
  end

external fun_to_js: int -> (t -> 'a) -> t = "caml_js_wrap_callback_strict"
external fun_to_js_args: (t -> 'a) -> t = "caml_ojs_wrap_fun_arguments"

let has_property o x =
  type_of o = "object" && o != null
  && get_prop o (string_to_js x) != undefined

external new_obj_arr: t -> t -> t = "caml_ojs_new_arr"

let empty_obj () = new_obj (get_prop_ascii global "Object") [||]

external iter_properties_untyped : t -> t -> unit = "caml_ojs_iterate_properties"
let iter_properties x f =
  iter_properties_untyped x (fun_to_js 1 (fun x -> f (string_of_js x)))

let apply_arr o arr = call o "apply" [| null; arr |]
let call_arr o s arr = call (get_prop o (string_to_js s)) "apply" [| o; arr |]

let is_null x =
  equals x null

let obj_type x =
  string_of_js (call (pure_js_expr "Object.prototype.toString") "call" [|x|])

module type T = sig
  type js := t
  type t
  val t_to_js : t -> js
  val t_of_js : js -> t
end

(* Ojs.T instances for built-in types *)
module Int = struct
  type t = int
  let t_to_js = int_to_js
  let t_of_js = int_of_js
 end
module String = struct
  type t = string
  let t_to_js = string_to_js
  let t_of_js = string_of_js
end
module Bool = struct
  type t = bool
  let t_to_js = bool_to_js
  let t_of_js = bool_of_js
end
module Float = struct
  type t = float
  let t_to_js = float_to_js
  let t_of_js = float_of_js
end
module Array (A: T) = struct
  type t = A.t array
  let t_to_js = array_to_js A.t_to_js
  let t_of_js = array_of_js A.t_of_js
end
module List (A: T) = struct
  type t = A.t list
  let t_to_js = list_to_js A.t_to_js
  let t_of_js = list_of_js A.t_of_js
end
module Option (A: T) = struct
  type t = A.t option
  let t_to_js = option_to_js A.t_to_js
  let t_of_js = option_of_js A.t_of_js
end


================================================
FILE: lib/ojs.mli
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** Binding with JS values. *)

type t
(** The universal type representing arbitrary JS values. *)

(** {2 Mapper for built-in types} *)

external t_of_js: t -> t = "%identity"
external t_to_js: t -> t = "%identity"

external string_of_js: t -> string = "caml_js_to_string"
external string_to_js: string -> t = "caml_js_from_string"

external int_of_js: t -> int = "%identity"
external int_to_js: int -> t = "%identity"

external bool_of_js: t -> bool = "caml_js_to_bool"
external bool_to_js: bool -> t = "caml_js_from_bool"

external float_of_js: t -> float = "caml_js_to_float"
external float_to_js: float -> t = "caml_js_from_float"

val array_of_js: (t -> 'a) -> t -> 'a array
val array_to_js: ('a -> t) -> 'a array -> t

val list_of_js: (t -> 'a) -> t -> 'a list
val list_to_js: ('a -> t) -> 'a list -> t

val array_of_js_from: (t -> 'a) -> t -> int -> 'a array
val list_of_js_from: (t -> 'a) -> t -> int -> 'a list

val option_of_js: (t -> 'a) -> t -> 'a option
(** Both [null] and [undefined] are mapped to [None]. *)

val option_to_js: ('a -> t) -> 'a option -> t
(** [None] is mapped to [null]. *)

val unit_of_js: t -> unit
val unit_to_js: unit -> t


(** {2 Wrap OCaml functions as JS functions} *)

external fun_to_js: int -> (t -> 'a) -> t = "caml_js_wrap_callback_strict"
(** Wrap an OCaml function of known arity (>=1) into a JS function.
    Extra arguments are discarded and missing argument are filled with
    'undefined'.
*)

external fun_to_js_args: (t -> 'a) -> t = "caml_ojs_wrap_fun_arguments"
(** Wrap an OCaml function taking JS arguments as a JS array. *)


(** {2 JS objects} *)

external get: t -> string -> t = "caml_js_get"
  [@@ocaml.deprecated "Use Ojs.get_prop_ascii instead."]

external set: t -> string -> t -> unit = "caml_js_set"
  [@@ocaml.deprecated "Use Ojs.set_prop_ascii instead."]

external delete: t -> string -> unit = "caml_js_delete"
  [@@ocaml.deprecated "Use Ojs.delete_prop_ascii instead."]

external get_prop_ascii: t -> string -> t = "caml_js_get"
  (** Get the property from an object (only works if the property key is a plain ascii string). *)

external set_prop_ascii: t -> string -> t -> unit = "caml_js_set"
  (** Set an object property (only works if the property key is a plain ascii string). *)

external delete_prop_ascii: t -> string -> unit = "caml_js_delete"
  (** Delete an object property (only works if the property key is a plain ascii string). *)

external get_prop: t -> t -> t = "caml_js_get"
  (** Get the property from an object. *)

external set_prop: t -> t -> t -> unit = "caml_js_set"
  (** Set an object property. *)

external delete_prop: t -> t -> unit = "caml_js_delete"
  (** Delete an object property. *)

external obj: (string * t) array -> t = "caml_js_object"

val empty_obj: unit -> t

val has_property: t -> string -> bool
val iter_properties: t -> (string -> unit) -> unit

(** {2 Calling JS functions} *)

external call: t -> string -> t array -> t = "caml_js_meth_call"
(** Call a method on an object (binding 'this' to the object). *)

external apply: t -> t array -> t = "caml_js_fun_call"
(** Call a function. *)

external new_obj: t -> t array -> t = "caml_js_new"
(** Call a constructor *)

val call_arr: t -> string -> t -> t
(** Variant of [Ojs.call] where the arguments are passed as an already
    built JS array. *)

val apply_arr: t -> t -> t
(** Variant of [Ojs.apply] where the arguments are passed as an already
    built JS array. *)

external new_obj_arr: t -> t -> t = "caml_ojs_new_arr"
(** Variant of [Ojs.new_obj] where the arguments are passed as an already
    built JS array. *)

(** {2 Arrays} *)

val array_make: int -> t
val array_get: t -> int -> t
val array_set: t -> int -> t -> unit

(** {2 Misc} *)

val global: t
val null: t

external variable: string -> t = "caml_js_var"

val type_of: t -> string

val instance_of: t -> constr:t -> bool

class obj: t ->
  object
    method to_js: t
  end

val is_null: t -> bool

val obj_type: t -> string
(** Returns:
    "[object Array]"
    "[object Object]"
    "[object Number]"
    "[object String]"
    "[object Null]"
    "[object Boolean]"
*)

module type T =
  sig
    type js := t
    type t
    val t_to_js : t -> js
    val t_of_js : js -> t
  end

(* Ojs.T instances for built-in types *)
module Int : T with type t = int
module String : T with type t = string
module Bool : T with type t = bool
module Float : T with type t = float
module Array (A: T) : T with type t = A.t array
module List (A: T) : T with type t = A.t list
module Option (A: T) : T with type t = A.t option


================================================
FILE: lib/ojs_exn.ml
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

type t = Jsoo_runtime.Error.t

external coerce : t -> Ojs.t = "%identity"
let name x = Ojs.string_of_js (Ojs.get_prop_ascii (coerce x) "name")
let message x = Ojs.string_of_js (Ojs.get_prop_ascii (coerce x) "message")
let stack x = Ojs.option_of_js Ojs.string_of_js (Ojs.get_prop_ascii (coerce x) "stack")
let to_string x = Ojs.string_of_js (Ojs.call (coerce x) "toString" [||])

exception Error = Jsoo_runtime.Error.Exn

let () =
  Printexc.register_printer (function
      | Error x -> Some (to_string x)
      | _ -> None
    )


================================================
FILE: lib/ojs_exn.mli
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

(** OCaml view on JS exceptions *)

type t

val name: t -> string
val message: t -> string
val stack: t -> string option
val to_string: t -> string

exception Error of t


================================================
FILE: lib/ojs_runtime.js
================================================
//Provides: caml_ojs_wrap_fun_arguments
//Requires: caml_js_wrap_callback
function caml_ojs_wrap_fun_arguments(f) {
  return function() {
    return caml_js_wrap_callback(f)(arguments);
  }
}

//Provides: caml_ojs_iterate_properties
//Requires: caml_js_to_string
function caml_ojs_iterate_properties(o, f) {
  var name;
  for(name in o) {
    if(o.hasOwnProperty(name)) {
      f(name);
    }
  }
}


================================================
FILE: lib/ojs_runtime_stubs.c
================================================
#include <stdlib.h>
#include <stdio.h>
void caml_ojs_wrap_fun_arguments () {
  fprintf(stderr, "Unimplemented JavaScript primitive caml_ojs_wrap_fun_arguments!\n");
  exit(1);
}
void caml_ojs_iterate_properties () {
  fprintf(stderr, "Unimplemented JavaScript primitive caml_ojs_iterate_properties!\n");
  exit(1);
}


================================================
FILE: node-test/bindings/arrays.mli
================================================
module JsArray (E: Ojs.T): sig
  type t
  val t_to_js: t -> Ojs.t
  val t_of_js: Ojs.t -> t

  val create: unit -> t [@@js.new "Array"]
  val push: t -> E.t -> unit [@@js.call]
  val pop: t -> E.t option [@@js.call]
end

module UntypedArray : sig
  include (module type of JsArray(Ojs))
end

module StringArray : sig
  include (module type of JsArray(Ojs.String))

  val join: t -> string -> string [@@js.call]
end

module[@js.scope "Array"] JsArray2: sig
  type 'a t
  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t

  val create: unit -> 'a t [@@js.create]
  val create': (module[@js] Ojs.T with type t = 'a) -> ('a list [@js.variadic]) -> 'a t [@@js.create]

  val push: (module[@js] Ojs.T with type t = 'a) -> 'a t -> 'a -> unit [@@js.call]
  val pop:  (module[@js] Ojs.T with type t = 'a) -> 'a t -> 'a option [@@js.call]

  val get: (module[@js] Ojs.T with type t = 'a) -> 'a t -> int -> 'a option [@@js.index_get]
  val set: (module[@js] Ojs.T with type t = 'a) -> 'a t -> int -> 'a -> unit [@@js.index_set]

  val join: string t -> string -> string [@@js.call]
end

================================================
FILE: node-test/bindings/buffer.mli
================================================
[@@@js.scope "Buffer"]

type t = private Ojs.t
val t_of_js: Ojs.t -> t
val t_to_js: t -> Ojs.t

val alloc: int -> t[@@js.global]
val from: string -> t[@@js.global]
val concat: t list -> t[@@js.global]

val length: t -> int [@@js.get]
val get: t -> int -> int option [@@js.index_get]
val set: t -> int -> int -> unit[@@js.index_set]
val write: t -> string -> int[@@js.call]
val slice: t -> int -> int -> t[@@js.call]
val to_string: t -> string[@@js.call]
val copy: t -> dst:t -> start:int -> dst_start:int -> dst_end:int -> int[@@js.call]


================================================
FILE: node-test/bindings/console.mli
================================================
[@@@js.scope "console"]

val log: 'a -> unit [@@js.global]
val error: 'a -> unit [@@js.global]

module T : sig
  val log: (module[@js] Ojs.T with type t = 'a) -> 'a -> unit [@@js.global]
  val error: (module[@js] Ojs.T with type t = 'a) -> 'a -> unit [@@js.global]
end

================================================
FILE: node-test/bindings/container.ml
================================================
module StringMap = struct
  include Map.Make(String)

  let t_to_js ml2js l =
    let o = Ojs.empty_obj () in
    iter (fun k v -> Ojs.set_prop o (Ojs.string_to_js k) (ml2js v)) l;
    o

  let t_of_js js2ml o =
    let l = ref empty in
    Ojs.iter_properties o
      (fun k -> l := add k (js2ml (Ojs.get_prop o (Ojs.string_to_js k))) !l);
    !l
end


================================================
FILE: node-test/bindings/container.mli
================================================
module StringMap : sig
  include Map.S with type key = string
  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
  val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t
end

================================================
FILE: node-test/bindings/dune
================================================
(library
 (name node)
 (synopsis "Bindings")
 (libraries ojs)
 (preprocess
  (pps gen_js_api.ppx))
 (modes byte)
 (js_of_ocaml
  (javascript_files imports.js))
 (wasm_of_ocaml
  (javascript_files imports.js imports.wat)))

(rule
 (targets imports.ml)
 (deps imports.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/imports.ml imports.ml)))

(rule
 (targets errors.ml)
 (deps errors.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/errors.ml errors.ml)))

(rule
 (targets global.ml)
 (deps global.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/global.ml global.ml)))

(rule
 (targets promise.ml)
 (deps promise.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/promise.ml promise.ml)))

(rule
 (targets buffer.ml)
 (deps buffer.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/buffer.ml buffer.ml)))

(rule
 (targets fs.ml)
 (deps fs.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/fs.ml fs.ml)))

(rule
 (targets path.ml)
 (deps path.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/path.ml path.ml)))

(rule
 (targets process.ml)
 (deps process.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/process.ml process.ml)))

(rule
 (targets console.ml)
 (deps console.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/console.ml console.ml)))

(rule
 (targets arrays.ml)
 (deps arrays.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/arrays.ml arrays.ml)))

(rule
 (targets number.ml)
 (deps number.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (action
  (diff expected/number.ml number.ml)))

================================================
FILE: node-test/bindings/errors.mli
================================================
module [@js.scope] Error : sig
  type t
  val t_to_js: t -> Ojs.t
  val t_of_js: Ojs.t -> t

  val create: string -> t [@@js.create]
  val stack_trace_limit: int [@@js.global]
  val set_stack_trace_limit: int -> unit [@@js.set]

  val code: t -> string [@@js.get]
  val message: t -> string [@@js.get]
  val stack: t -> string [@@js.get]
end


================================================
FILE: node-test/bindings/expected/arrays.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
module JsArray(E:Ojs.T) =
  struct
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x2 : Ojs.t) -> x2
    and t_to_js : t -> Ojs.t = fun (x1 : Ojs.t) -> x1
    let create : unit -> t =
      fun () ->
        t_of_js (Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||])
    let push : t -> E.t -> unit =
      fun (x4 : t) (x3 : E.t) ->
        ignore (Ojs.call (t_to_js x4) "push" [|(E.t_to_js x3)|])
    let pop : t -> E.t option =
      fun (x5 : t) ->
        Ojs.option_of_js E.t_of_js (Ojs.call (t_to_js x5) "pop" [||])
  end
module UntypedArray = struct include (JsArray)(Ojs) end
module StringArray =
  struct
    include (JsArray)(Ojs.String)
    let join : t -> string -> string =
      fun (x8 : t) (x7 : string) ->
        Ojs.string_of_js
          (Ojs.call (t_to_js x8) "join" [|(Ojs.string_to_js x7)|])
  end
module JsArray2 =
  struct
    type 'a t = Ojs.t
    let rec t_of_js : 'a . (Ojs.t -> 'a) -> Ojs.t -> 'a t =
      fun (type __a) (__a_of_js : Ojs.t -> __a) -> fun (x10 : Ojs.t) -> x10
    and t_to_js : 'a . ('a -> Ojs.t) -> 'a t -> Ojs.t =
      fun (type __a) (__a_to_js : __a -> Ojs.t) -> fun (x9 : Ojs.t) -> x9
    let create : unit -> 'a t =
      fun () ->
        t_of_js Obj.magic
          (Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||])
    let create' : (module Ojs.T with type t = 'a) -> 'a list -> 'a t =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x12 : a list) ->
          t_of_js A.t_of_js
            (Ojs.new_obj_arr (Ojs.get_prop_ascii Ojs.global "Array")
               (let x13 =
                  Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||] in
                List.iter
                  (fun (x14 : a) ->
                     ignore (Ojs.call x13 "push" [|(A.t_to_js x14)|])) x12;
                x13))
    let push : (module Ojs.T with type t = 'a) -> 'a t -> 'a -> unit =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x17 : a t)
          (x16 : a) ->
          ignore
            (Ojs.call (t_to_js A.t_to_js x17) "push" [|(A.t_to_js x16)|])
    let pop : (module Ojs.T with type t = 'a) -> 'a t -> 'a option =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x19 : a t) ->
          Ojs.option_of_js A.t_of_js
            (Ojs.call (t_to_js A.t_to_js x19) "pop" [||])
    let get : (module Ojs.T with type t = 'a) -> 'a t -> int -> 'a option =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x22 : a t)
          (x24 : int) ->
          Ojs.option_of_js A.t_of_js
            (Ojs.array_get (t_to_js A.t_to_js x22) x24)
    let set : (module Ojs.T with type t = 'a) -> 'a t -> int -> 'a -> unit =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x26 : a t)
          (x28 : int) (x29 : a) ->
          Ojs.array_set (t_to_js A.t_to_js x26) x28 (A.t_to_js x29)
    let join : string t -> string -> string =
      fun (x31 : string t) (x30 : string) ->
        Ojs.string_of_js
          (Ojs.call (t_to_js Ojs.string_to_js x31) "join"
             [|(Ojs.string_to_js x30)|])
  end


================================================
FILE: node-test/bindings/expected/buffer.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
type t = Ojs.t
let rec t_of_js : Ojs.t -> t = fun (x2 : Ojs.t) -> x2
and t_to_js : t -> Ojs.t = fun (x1 : Ojs.t) -> x1
let alloc : int -> t =
  fun (x3 : int) ->
    t_of_js
      (Ojs.call (Ojs.get_prop_ascii Ojs.global "Buffer") "alloc"
         [|(Ojs.int_to_js x3)|])
let from : string -> t =
  fun (x4 : string) ->
    t_of_js
      (Ojs.call (Ojs.get_prop_ascii Ojs.global "Buffer") "from"
         [|(Ojs.string_to_js x4)|])
let concat : t list -> t =
  fun (x5 : t list) ->
    t_of_js
      (Ojs.call (Ojs.get_prop_ascii Ojs.global "Buffer") "concat"
         [|(Ojs.list_to_js t_to_js x5)|])
let length : t -> int =
  fun (x7 : t) -> Ojs.int_of_js (Ojs.get_prop_ascii (t_to_js x7) "length")
let get : t -> int -> int option =
  fun (x8 : t) (x9 : int) ->
    Ojs.option_of_js Ojs.int_of_js (Ojs.array_get (t_to_js x8) x9)
let set : t -> int -> int -> unit =
  fun (x11 : t) (x12 : int) (x13 : int) ->
    Ojs.array_set (t_to_js x11) x12 (Ojs.int_to_js x13)
let write : t -> string -> int =
  fun (x15 : t) (x14 : string) ->
    Ojs.int_of_js (Ojs.call (t_to_js x15) "write" [|(Ojs.string_to_js x14)|])
let slice : t -> int -> int -> t =
  fun (x18 : t) (x16 : int) (x17 : int) ->
    t_of_js
      (Ojs.call (t_to_js x18) "slice"
         [|(Ojs.int_to_js x16);(Ojs.int_to_js x17)|])
let to_string : t -> string =
  fun (x19 : t) -> Ojs.string_of_js (Ojs.call (t_to_js x19) "toString" [||])
let copy : t -> dst:t -> start:int -> dst_start:int -> dst_end:int -> int =
  fun (x24 : t) ~dst:(x20 : t) ~start:(x21 : int) ~dst_start:(x22 : int)
    ~dst_end:(x23 : int) ->
    Ojs.int_of_js
      (Ojs.call (t_to_js x24) "copy"
         [|(t_to_js x20);(Ojs.int_to_js x21);(Ojs.int_to_js x22);(Ojs.int_to_js
                                                                    x23)|])


================================================
FILE: node-test/bindings/expected/console.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
let log : 'a -> unit =
  fun (x1 : 'a) ->
    ignore
      (Ojs.call (Ojs.get_prop_ascii Ojs.global "console") "log"
         [|(Obj.magic x1)|])
let error : 'a -> unit =
  fun (x2 : 'a) ->
    ignore
      (Ojs.call (Ojs.get_prop_ascii Ojs.global "console") "error"
         [|(Obj.magic x2)|])
module T =
  struct
    let log : (module Ojs.T with type t = 'a) -> 'a -> unit =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x3 : a) ->
          ignore
            (Ojs.call (Ojs.get_prop_ascii Ojs.global "console") "log"
               [|(A.t_to_js x3)|])
    let error : (module Ojs.T with type t = 'a) -> 'a -> unit =
      fun (type a) ->
        fun ((module A)  : (module Ojs.T with type t = a)) (x4 : a) ->
          ignore
            (Ojs.call (Ojs.get_prop_ascii Ojs.global "console") "error"
               [|(A.t_to_js x4)|])
  end


================================================
FILE: node-test/bindings/expected/errors.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
module Error =
  struct
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x2 : Ojs.t) -> x2
    and t_to_js : t -> Ojs.t = fun (x1 : Ojs.t) -> x1
    let create : string -> t =
      fun (x3 : string) ->
        t_of_js
          (Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Error")
             [|(Ojs.string_to_js x3)|])
    let stack_trace_limit : int =
      Ojs.int_of_js
        (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "Error")
           "stackTraceLimit")
    let set_stack_trace_limit : int -> unit =
      fun (x4 : int) ->
        Ojs.set_prop_ascii (Ojs.get_prop_ascii Ojs.global "Error")
          "stackTraceLimit" (Ojs.int_to_js x4)
    let code : t -> string =
      fun (x5 : t) ->
        Ojs.string_of_js (Ojs.get_prop_ascii (t_to_js x5) "code")
    let message : t -> string =
      fun (x6 : t) ->
        Ojs.string_of_js (Ojs.get_prop_ascii (t_to_js x6) "message")
    let stack : t -> string =
      fun (x7 : t) ->
        Ojs.string_of_js (Ojs.get_prop_ascii (t_to_js x7) "stack")
  end


================================================
FILE: node-test/bindings/expected/fs.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
module Dirent =
  struct
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x2 : Ojs.t) -> x2
    and t_to_js : t -> Ojs.t = fun (x1 : Ojs.t) -> x1
    let name : t -> string =
      fun (x3 : t) ->
        Ojs.string_of_js (Ojs.get_prop_ascii (t_to_js x3) "name")
    let is_file : t -> bool =
      fun (x4 : t) -> Ojs.bool_of_js (Ojs.call (t_to_js x4) "isFile" [||])
    let is_directory : t -> bool =
      fun (x5 : t) ->
        Ojs.bool_of_js (Ojs.call (t_to_js x5) "isDirectory" [||])
  end
module Dir =
  struct
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x7 : Ojs.t) -> x7
    and t_to_js : t -> Ojs.t = fun (x6 : Ojs.t) -> x6
    let path : t -> string =
      fun (x8 : t) ->
        Ojs.string_of_js (Ojs.get_prop_ascii (t_to_js x8) "path")
    let close : t -> unit Promise.t =
      fun (x9 : t) ->
        Promise.t_of_js Ojs.unit_of_js (Ojs.call (t_to_js x9) "close" [||])
    let read : t -> Dirent.t option Promise.t =
      fun (x11 : t) ->
        Promise.t_of_js
          (fun (x12 : Ojs.t) -> Ojs.option_of_js Dirent.t_of_js x12)
          (Ojs.call (t_to_js x11) "read" [||])
  end
module FileHandle =
  struct
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x15 : Ojs.t) -> x15
    and t_to_js : t -> Ojs.t = fun (x14 : Ojs.t) -> x14
    type read = {
      bytes_read: int ;
      buffer: Buffer.t }
    let rec read_of_js : Ojs.t -> read =
      fun (x17 : Ojs.t) ->
        {
          bytes_read = (Ojs.int_of_js (Ojs.get_prop_ascii x17 "bytesRead"));
          buffer = (Buffer.t_of_js (Ojs.get_prop_ascii x17 "buffer"))
        }
    and read_to_js : read -> Ojs.t =
      fun (x16 : read) ->
        Ojs.obj
          [|("bytesRead", (Ojs.int_to_js x16.bytes_read));("buffer",
                                                            (Buffer.t_to_js
                                                               x16.buffer))|]
    let append_file : t -> Buffer.t -> unit Promise.t =
      fun (x19 : t) (x18 : Buffer.t) ->
        Promise.t_of_js Ojs.unit_of_js
          (Ojs.call (t_to_js x19) "appendFile" [|(Buffer.t_to_js x18)|])
    let read : t -> Buffer.t -> int -> int -> int -> read Promise.t =
      fun (x25 : t) (x21 : Buffer.t) (x22 : int) (x23 : int) (x24 : int) ->
        Promise.t_of_js read_of_js
          (Ojs.call (t_to_js x25) "read"
             [|(Buffer.t_to_js x21);(Ojs.int_to_js x22);(Ojs.int_to_js x23);(
               Ojs.int_to_js x24)|])
    let chmod : t -> int -> unit Promise.t =
      fun (x28 : t) (x27 : int) ->
        Promise.t_of_js Ojs.unit_of_js
          (Ojs.call (t_to_js x28) "chmod" [|(Ojs.int_to_js x27)|])
    let chmown : t -> uid:int -> gid:int -> unit Promise.t =
      fun (x32 : t) ~uid:(x30 : int) ~gid:(x31 : int) ->
        Promise.t_of_js Ojs.unit_of_js
          (Ojs.call (t_to_js x32) "chmown"
             [|(Ojs.int_to_js x30);(Ojs.int_to_js x31)|])
    let close : t -> unit Promise.t =
      fun (x34 : t) ->
        Promise.t_of_js Ojs.unit_of_js (Ojs.call (t_to_js x34) "close" [||])
    let datasync : t -> unit Promise.t =
      fun (x36 : t) ->
        Promise.t_of_js Ojs.unit_of_js
          (Ojs.call (t_to_js x36) "datasync" [||])
    let fd : t -> int =
      fun (x38 : t) -> Ojs.int_of_js (Ojs.get_prop_ascii (t_to_js x38) "fd")
  end
let readdir : string -> string list Promise.t =
  fun (x39 : string) ->
    Promise.t_of_js
      (fun (x40 : Ojs.t) -> Ojs.list_of_js Ojs.string_of_js x40)
      (Ojs.call
         (Ojs.get_prop_ascii (Jsoo_runtime.Js.runtime_value "node_fs")
            "promises") "readdir" [|(Ojs.string_to_js x39)|])
let open_ : string -> flag:string -> FileHandle.t Promise.t =
  fun (x42 : string) ~flag:(x43 : string) ->
    Promise.t_of_js FileHandle.t_of_js
      (Ojs.call
         (Ojs.get_prop_ascii (Jsoo_runtime.Js.runtime_value "node_fs")
            "promises") "open"
         [|(Ojs.string_to_js x42);(Ojs.string_to_js x43)|])
let rmdir : string -> unit Promise.t =
  fun (x45 : string) ->
    Promise.t_of_js Ojs.unit_of_js
      (Ojs.call
         (Ojs.get_prop_ascii (Jsoo_runtime.Js.runtime_value "node_fs")
            "promises") "rmdir" [|(Ojs.string_to_js x45)|])
let rename : string -> string -> unit Promise.t =
  fun (x47 : string) (x48 : string) ->
    Promise.t_of_js Ojs.unit_of_js
      (Ojs.call
         (Ojs.get_prop_ascii (Jsoo_runtime.Js.runtime_value "node_fs")
            "promises") "rename"
         [|(Ojs.string_to_js x47);(Ojs.string_to_js x48)|])
let unlink : string -> unit Promise.t =
  fun (x50 : string) ->
    Promise.t_of_js Ojs.unit_of_js
      (Ojs.call
         (Ojs.get_prop_ascii (Jsoo_runtime.Js.runtime_value "node_fs")
            "promises") "unlink" [|(Ojs.string_to_js x50)|])


================================================
FILE: node-test/bindings/expected/global.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
type timeout_id = Ojs.t
let rec timeout_id_of_js : Ojs.t -> timeout_id = fun (x2 : Ojs.t) -> x2
and timeout_id_to_js : timeout_id -> Ojs.t = fun (x1 : Ojs.t) -> x1
type interval_id = Ojs.t
let rec interval_id_of_js : Ojs.t -> interval_id = fun (x4 : Ojs.t) -> x4
and interval_id_to_js : interval_id -> Ojs.t = fun (x3 : Ojs.t) -> x3
let set_interval : (unit -> unit) -> int -> interval_id =
  fun (x5 : unit -> unit) (x6 : int) ->
    interval_id_of_js
      (Ojs.call Ojs.global "setInterval"
         [|(Ojs.fun_to_js 1 (fun _ -> x5 ()));(Ojs.int_to_js x6)|])
let set_timeout : (unit -> unit) -> int -> timeout_id =
  fun (x7 : unit -> unit) (x8 : int) ->
    timeout_id_of_js
      (Ojs.call Ojs.global "setTimeout"
         [|(Ojs.fun_to_js 1 (fun _ -> x7 ()));(Ojs.int_to_js x8)|])
let clear_timeout : timeout_id -> unit =
  fun (x9 : timeout_id) ->
    ignore (Ojs.call Ojs.global "clearTimeout" [|(timeout_id_to_js x9)|])
let clear_interval : interval_id -> unit =
  fun (x10 : interval_id) ->
    ignore (Ojs.call Ojs.global "clearInterval" [|(interval_id_to_js x10)|])


================================================
FILE: node-test/bindings/expected/imports.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
let path : Ojs.t = Jsoo_runtime.Js.runtime_value "node_path"


================================================
FILE: node-test/bindings/expected/number.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
type t = Ojs.t
let rec t_of_js : Ojs.t -> t = fun (x2 : Ojs.t) -> x2
and t_to_js : t -> Ojs.t = fun (x1 : Ojs.t) -> x1
let toString : t -> ?radix:int -> unit -> float =
  fun (x6 : t) ?radix:(x3 : int option) () ->
    Ojs.float_of_js
      (let x7 = t_to_js x6 in
       Ojs.call (Ojs.get_prop_ascii x7 "toString") "apply"
         [|x7;((let x4 =
                  Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||] in
                (match x3 with
                 | Some x5 ->
                     ignore (Ojs.call x4 "push" [|(Ojs.int_to_js x5)|])
                 | None -> ());
                x4))|])
let toFixed : t -> ?fractionDigits:int -> unit -> float =
  fun (x11 : t) ?fractionDigits:(x8 : int option) () ->
    Ojs.float_of_js
      (let x12 = t_to_js x11 in
       Ojs.call (Ojs.get_prop_ascii x12 "toFixed") "apply"
         [|x12;((let x9 =
                   Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||] in
                 (match x8 with
                  | Some x10 ->
                      ignore (Ojs.call x9 "push" [|(Ojs.int_to_js x10)|])
                  | None -> ());
                 x9))|])
let toExponential : t -> ?fractionDigits:int -> unit -> float =
  fun (x16 : t) ?fractionDigits:(x13 : int option) () ->
    Ojs.float_of_js
      (let x17 = t_to_js x16 in
       Ojs.call (Ojs.get_prop_ascii x17 "toExponential") "apply"
         [|x17;((let x14 =
                   Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||] in
                 (match x13 with
                  | Some x15 ->
                      ignore (Ojs.call x14 "push" [|(Ojs.int_to_js x15)|])
                  | None -> ());
                 x14))|])
let toPrecision : t -> ?precision:int -> unit -> float =
  fun (x21 : t) ?precision:(x18 : int option) () ->
    Ojs.float_of_js
      (let x22 = t_to_js x21 in
       Ojs.call (Ojs.get_prop_ascii x22 "toPrecision") "apply"
         [|x22;((let x19 =
                   Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||] in
                 (match x18 with
                  | Some x20 ->
                      ignore (Ojs.call x19 "push" [|(Ojs.int_to_js x20)|])
                  | None -> ());
                 x19))|])
let valueOf : t -> float =
  fun (x23 : t) -> Ojs.float_of_js (Ojs.call (t_to_js x23) "valueOf" [||])
module Scoped =
  struct
    let create : 'any -> t =
      fun (x24 : 'any) ->
        t_of_js
          (Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Number")
             [|(Obj.magic x24)|])
    let invoke : 'any -> float =
      fun (x25 : 'any) ->
        Ojs.float_of_js
          (Ojs.apply (Ojs.get_prop_ascii Ojs.global "Number")
             [|(Obj.magic x25)|])
    let min_value : float =
      Ojs.float_of_js
        (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "Number")
           "MIN_VALUE")
    let max_value : float =
      Ojs.float_of_js
        (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "Number")
           "MAX_VALUE")
    let nan : float =
      Ojs.float_of_js
        (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "Number") "NaN")
    let negative_infinity : float =
      Ojs.float_of_js
        (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "Number")
           "NEGATIVE_INFINITY")
    let positive_infinity : float =
      Ojs.float_of_js
        (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "Number")
           "POSITIVE_INFINITY")
  end
module Static =
  struct
    type number = t
    let rec number_of_js : Ojs.t -> number = fun (x27 : Ojs.t) -> t_of_js x27
    and number_to_js : number -> Ojs.t = fun (x26 : t) -> t_to_js x26
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x29 : Ojs.t) -> x29
    and t_to_js : t -> Ojs.t = fun (x28 : Ojs.t) -> x28
    let create : t -> 'any -> number =
      fun (x31 : t) (x30 : 'any) ->
        number_of_js (Ojs.new_obj (t_to_js x31) [|(Obj.magic x30)|])
    let apply : t -> 'any -> float =
      fun (x33 : t) (x32 : 'any) ->
        Ojs.float_of_js (Ojs.apply (t_to_js x33) [|(Obj.magic x32)|])
    let min_value : t -> float =
      fun (x34 : t) ->
        Ojs.float_of_js (Ojs.get_prop_ascii (t_to_js x34) "MIN_VALUE")
    let max_value : t -> float =
      fun (x35 : t) ->
        Ojs.float_of_js (Ojs.get_prop_ascii (t_to_js x35) "MAX_VALUE")
    let nan : t -> float =
      fun (x36 : t) ->
        Ojs.float_of_js (Ojs.get_prop_ascii (t_to_js x36) "NaN")
    let negative_infinity : t -> float =
      fun (x37 : t) ->
        Ojs.float_of_js
          (Ojs.get_prop_ascii (t_to_js x37) "NEGATIVE_INFINITY")
    let positive_infinity : t -> float =
      fun (x38 : t) ->
        Ojs.float_of_js
          (Ojs.get_prop_ascii (t_to_js x38) "POSITIVE_INFINITY")
  end
let number : Static.t =
  Static.t_of_js (Ojs.get_prop_ascii Ojs.global "Number")


================================================
FILE: node-test/bindings/expected/path.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
let sep : string = Ojs.string_of_js (Ojs.get_prop_ascii Imports.path "sep")
let dirname : string -> string =
  fun (x1 : string) ->
    Ojs.string_of_js
      (Ojs.call Imports.path "dirname" [|(Ojs.string_to_js x1)|])
let extname : string -> string =
  fun (x2 : string) ->
    Ojs.string_of_js
      (Ojs.call Imports.path "extname" [|(Ojs.string_to_js x2)|])
let is_absolute : string -> bool =
  fun (x3 : string) ->
    Ojs.bool_of_js
      (Ojs.call Imports.path "isAbsolute" [|(Ojs.string_to_js x3)|])
let join : string list -> string =
  fun (x4 : string list) ->
    Ojs.string_of_js
      (let x7 = Imports.path in
       Ojs.call (Ojs.get_prop_ascii x7 "join") "apply"
         [|x7;((let x5 =
                  Ojs.new_obj (Ojs.get_prop_ascii Ojs.global "Array") [||] in
                List.iter
                  (fun (x6 : string) ->
                     ignore (Ojs.call x5 "push" [|(Ojs.string_to_js x6)|]))
                  x4;
                x5))|])
let normalize : string -> string =
  fun (x8 : string) ->
    Ojs.string_of_js
      (Ojs.call Imports.path "normalize" [|(Ojs.string_to_js x8)|])
type parse_result =
  {
  dir: string ;
  root: string ;
  base: string ;
  name: string ;
  ext: string }
let rec parse_result_of_js : Ojs.t -> parse_result =
  fun (x10 : Ojs.t) ->
    {
      dir = (Ojs.string_of_js (Ojs.get_prop_ascii x10 "dir"));
      root = (Ojs.string_of_js (Ojs.get_prop_ascii x10 "root"));
      base = (Ojs.string_of_js (Ojs.get_prop_ascii x10 "base"));
      name = (Ojs.string_of_js (Ojs.get_prop_ascii x10 "name"));
      ext = (Ojs.string_of_js (Ojs.get_prop_ascii x10 "ext"))
    }
and parse_result_to_js : parse_result -> Ojs.t =
  fun (x9 : parse_result) ->
    Ojs.obj
      [|("dir", (Ojs.string_to_js x9.dir));("root",
                                             (Ojs.string_to_js x9.root));
        ("base", (Ojs.string_to_js x9.base));("name",
                                               (Ojs.string_to_js x9.name));
        ("ext", (Ojs.string_to_js x9.ext))|]
let parse : string -> parse_result =
  fun (x11 : string) ->
    parse_result_of_js
      (Ojs.call Imports.path "parse" [|(Ojs.string_to_js x11)|])


================================================
FILE: node-test/bindings/expected/process.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
let env : string Container.StringMap.t =
  Container.StringMap.t_of_js Ojs.string_of_js
    (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "process") "env")
let version : string option =
  Ojs.option_of_js Ojs.string_of_js
    (Ojs.get_prop_ascii (Ojs.get_prop_ascii Ojs.global "process") "version")


================================================
FILE: node-test/bindings/expected/promise.ml
================================================
[@@@js.dummy "!! This code has been generated by gen_js_api !!"]
[@@@ocaml.warning "-7-32-39"]
module UntypedPromise =
  struct
    type t = Ojs.t
    let rec t_of_js : Ojs.t -> t = fun (x2 : Ojs.t) -> x2
    and t_to_js : t -> Ojs.t = fun (x1 : Ojs.t) -> x1
    let resolve : Ojs.t -> Ojs.t =
      fun (x3 : Ojs.t) ->
        Ojs.call (Ojs.get_prop_ascii Ojs.global "Promise") "resolve" [|x3|]
    let reject : Ojs.t -> Ojs.t =
      fun (x4 : Ojs.t) ->
        Ojs.call (Ojs.get_prop_ascii Ojs.global "Promise") "reject" [|x4|]
    let then_ :
      Ojs.t -> success:(Ojs.t -> Ojs.t) -> error:(Ojs.t -> Ojs.t) -> Ojs.t =
      fun (x9 : Ojs.t) ~success:(x5 : Ojs.t -> Ojs.t)
        ~error:(x7 : Ojs.t -> Ojs.t) ->
        Ojs.call x9 "then" [|(Ojs.fun_to_js 1 x5);(Ojs.fun_to_js 1 x7)|]
    let all : Ojs.t list -> Ojs.t =
      fun (x10 : Ojs.t list) ->
        Ojs.call (Ojs.get_prop_ascii Ojs.global "Promise") "all"
          [|(Ojs.list_to_js (fun (x11 : Ojs.t) -> x11) x10)|]
    include
      struct
        type wrap = {
          content: Ojs.t }
        [@@@ocaml.warning "-7-32-39"]
        let rec wrap_of_js : Ojs.t -> wrap =
          fun (x13 : Ojs.t) ->
            { content = (Ojs.get_prop_ascii x13 "content") }
        and wrap_to_js : wrap -> Ojs.t =
          fun (x12 : wrap) -> Ojs.obj [|("content", (x12.content))|]
      end
    let is_promise o = (resolve o) == o
    let wrap o = if is_promise o then wrap_to_js { content = o } else o
    let unwrap o =
      if Ojs.has_property o "content"
      then Ojs.get_prop_ascii o "content"
      else o
    let return x = resolve (wrap x)
    let fail err = reject (wrap err)
    let bind ?(error= fail) p f =
      then_ p ~success:(fun x -> f (unwrap x))
        ~error:(fun x -> error (unwrap x))
  end
type 'a t = UntypedPromise.t
type error = Ojs.t
let fail error = UntypedPromise.fail error
let return x = UntypedPromise.return (Obj.magic x)
let bind ?error p f = UntypedPromise.bind ?error p (fun x -> f (Obj.magic x))
let prod p1 p2 =
  bind (UntypedPromise.all [p1; p2])
    (fun ojs ->
       match Ojs.list_of_js Ojs.t_of_js ojs with
       | x1::x2::[] -> return (x1, x2)
       | _ -> assert false)
let map f p = bind p (fun x -> return (f x))
let t_to_js f p = UntypedPromise.t_to_js (map f p)
let t_of_js f p = map f (UntypedPromise.t_of_js p)
let (let+) p f = map f p
let (and+) = prod
let ( let* ) p f = bind p f
let ( and* ) = prod
let catch p error = bind p ~error return


================================================
FILE: node-test/bindings/fs.mli
================================================
[@@@js.scope "@node_fs.promises"]

module Dirent : sig
  type t = Ojs.t
  val t_of_js: Ojs.t -> t
  val t_to_js: t -> Ojs.t

  val name: t -> string [@@js.get]
  val is_file: t -> bool [@@js.call]
  val is_directory: t -> bool [@@js.call]
end

module Dir : sig
  type t = Ojs.t
  val t_of_js: Ojs.t -> t
  val t_to_js: t -> Ojs.t


  val path: t -> string [@@js.get]
  val close: t -> unit Promise.t [@@js.call]
  val read:t -> Dirent.t option Promise.t [@@js.call]
end

module FileHandle : sig
  type t = Ojs.t
  val t_of_js: Ojs.t -> t
  val t_to_js: t -> Ojs.t

  type read = {
    bytes_read: int;
    buffer: Buffer.t;
  }

  val append_file: t -> Buffer.t -> unit Promise.t [@@js.call]
  val read: t -> Buffer.t -> int -> int -> int -> read Promise.t [@@js.call]
  val chmod: t -> int -> unit Promise.t [@@js.call]
  val chmown: t -> uid:int -> gid:int -> unit Promise.t [@@js.call]
  val close: t -> unit Promise.t [@@js.call]
  val datasync: t -> unit Promise.t [@@js.call]
  val fd: t -> int [@@js.get]
end

val readdir: string -> string list Promise.t [@@js.global]
val open_: string -> flag:string -> FileHandle.t Promise.t [@@js.global]
val rmdir: string -> unit Promise.t [@@js.global]
val rename: string -> string -> unit Promise.t [@@js.global]
val unlink: string -> unit Promise.t [@@js.global]


================================================
FILE: node-test/bindings/global.mli
================================================
type timeout_id
val timeout_id_to_js: timeout_id -> Ojs.t
val timeout_id_of_js: Ojs.t -> timeout_id

type interval_id
val interval_id_to_js: interval_id -> Ojs.t
val interval_id_of_js: Ojs.t -> interval_id


val set_interval: (unit -> unit) -> int -> interval_id [@@js.global]
val set_timeout: (unit -> unit) -> int -> timeout_id [@@js.global]
val clear_timeout: timeout_id -> unit [@@js.global]
val clear_interval: interval_id -> unit [@@js.global]


================================================
FILE: node-test/bindings/imports.js
================================================
//Provides: node_path
var node_path = require('path');

//Provides: node_fs
var node_fs = require('fs');


================================================
FILE: node-test/bindings/imports.mli
================================================
val path: Ojs.t [@@js.global "@node_path"]


================================================
FILE: node-test/bindings/imports.wat
================================================

(global (export "_node_path") (import "js" "node_path") anyref)
(global (export "_node_fs") (import "js" "node_fs") anyref)


================================================
FILE: node-test/bindings/number.mli
================================================
type t = private Ojs.t

val toString: t -> ?radix:int -> unit -> float [@@js.call]
val toFixed: t -> ?fractionDigits:int -> unit -> float [@@js.call]
val toExponential: t -> ?fractionDigits:int -> unit -> float [@@js.call]
val toPrecision: t -> ?precision:int -> unit -> float [@@js.call]
val valueOf: t -> float [@@js.call]

(* scoped *)

module [@js.scope "Number"] Scoped : sig
  val create: 'any -> t [@@js.create]
  val invoke: 'any -> float [@@js.invoke]

  val min_value: float [@@js.global "MIN_VALUE"]
  val max_value: float [@@js.global "MAX_VALUE"]
  val nan: float [@@js.global "NaN"]
  val negative_infinity: float [@@js.global "NEGATIVE_INFINITY"]
  val positive_infinity: float [@@js.global "POSITIVE_INFINITY"]
end

(* non-scoped *)

module Static : sig
  type number = t
  type t = private Ojs.t

  val create: t -> 'any -> number [@@js.apply_newable]
  val apply: t -> 'any -> float [@@js.apply]

  val min_value: t -> float [@@js.get "MIN_VALUE"]
  val max_value: t -> float [@@js.get "MAX_VALUE"]
  val nan: t -> float [@@js.get "NaN"]
  val negative_infinity: t -> float [@@js.get "NEGATIVE_INFINITY"]
  val positive_infinity: t -> float [@@js.get "POSITIVE_INFINITY"]
end
val number: Static.t [@@js.global "Number"]


================================================
FILE: node-test/bindings/path.mli
================================================
[@@@js.scope Imports.path]

val sep: string [@@js.global]
val dirname: string -> string [@@js.global]
val extname: string -> string [@@js.global]
val is_absolute: string -> bool [@@js.global]
val join: (string list [@js.variadic]) -> string [@@js.global]
val normalize: string -> string [@@js.global]

type parse_result =
  {
    dir: string;
    root: string;
    base: string;
    name: string;
    ext: string
  }

val parse: string -> parse_result [@@js.global]


================================================
FILE: node-test/bindings/process.mli
================================================
[@@@js.scope "process"]

val env : string Container.StringMap.t [@@js.global]
val version: string option [@@js.global]

================================================
FILE: node-test/bindings/promise.mli
================================================
module UntypedPromise : sig

  type t = private Ojs.t
  val t_to_js: t -> Ojs.t
  val t_of_js: Ojs.t -> t

  [@@@js.stop]
  val return: Ojs.t -> t
  val fail: Ojs.t -> t
  val bind: ?error:(Ojs.t -> t) -> t -> (Ojs.t -> t) -> t
  val all: Ojs.t list -> t
  [@@@js.start]

  [@@@js.implem
    val resolve: Ojs.t -> Ojs.t [@@js.global "Promise.resolve"]
    val reject: Ojs.t -> Ojs.t [@@js.global "Promise.reject"]
    val then_: Ojs.t -> success:(Ojs.t -> Ojs.t) -> error:(Ojs.t -> Ojs.t) -> Ojs.t [@@js.call "then"]
    val all: Ojs.t list -> Ojs.t [@@js.global "Promise.all"]

    type wrap = { content: Ojs.t }[@@js]

    let is_promise o =
      resolve o == o

    let wrap o =
      if is_promise o then
        wrap_to_js { content = o }
      else o

    let unwrap o =
      if Ojs.has_property o "content" then
        Ojs.get_prop_ascii o "content"
      else
        o

    let return x = resolve (wrap x)
    let fail err = reject (wrap err)
    let bind ?(error = fail) p f =
      then_ p ~success:(fun x -> f (unwrap x))
        ~error:(fun x -> error (unwrap x))

  ]
end

[@@@js.stop]
type 'a t
val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t
val t_of_js: (Ojs.t -> 'a) -> Ojs.t -> 'a t

type error = Ojs.t

val fail: error -> 'a t
val return: 'a -> 'a t
val bind: ?error:(error -> 'b t) -> 'a t -> ('a -> 'b t) -> 'b t
val map: ('a -> 'b) -> 'a t -> 'b t
val prod: 'a t -> 'b t -> ('a * 'b) t

val ( let+ ): 'a t -> ('a -> 'b) -> 'b t
val ( and+ ): 'a t -> 'b t -> ('a * 'b) t
val ( let* ): 'a t -> ('a -> 'b t) -> 'b t
val ( and* ): 'a t -> 'b t -> ('a * 'b) t

val catch: 'a t -> (error -> 'a t) -> 'a t

[@@@js.start]
[@@@js.implem
  type 'a t = UntypedPromise.t
  type error = Ojs.t
  let fail error = UntypedPromise.fail  error
  let return x = UntypedPromise.return (Obj.magic x)
  let bind ?error p f =
    UntypedPromise.bind ?error p
      (fun x -> f (Obj.magic x))

  let prod p1 p2 =
    bind (UntypedPromise.all [p1; p2])
      (fun ojs ->
         match Ojs.list_of_js Ojs.t_of_js ojs with
         | [x1; x2] -> return (x1, x2)
         | _ -> assert false
      )
  let map f p = bind p (fun x -> return (f x))
  let t_to_js f p = UntypedPromise.t_to_js (map f p)
  let t_of_js f p = map f (UntypedPromise.t_of_js p)

  let (let+) p f = map f p
  let (and+) = prod
  let (let*) p f = bind p f
  let (and*) = prod

  let catch p error = bind p ~error return

]


================================================
FILE: node-test/runtime_primitives/bindings.mli
================================================
module [@js.scope "@node_fs"] Fs : sig
  val write_file_sync : string -> string -> unit [@@js.global "writeFileSync"]
  val read_file_sync : string -> encoding:string -> string [@@js.global "readFileSync"]
  val readdir_sync : string -> string array [@@js.global "readdirSync"]
  val append_file_sync : string -> string -> unit [@@js.global "appendFileSync"]
end

module [@js.scope "@node_path"] Path : sig
  val separator: string [@@js.global "sep"]
  val join : (string list [@js.variadic]) -> string [@@js.global "join"]
end

val node_version : string [@@js.global "@node_version"]
val log : string -> unit [@@js.global "@node_console"]


================================================
FILE: node-test/runtime_primitives/dune
================================================
(rule
 (targets bindings.ml)
 (deps bindings.mli)
 (action
  (run gen_js_api %{deps})))

(executable
 (name example)
 (libraries ojs)
 (preprocess
  (pps gen_js_api.ppx))
 (modes js wasm)
 (js_of_ocaml
  (javascript_files imports.js))
 (wasm_of_ocaml
  (javascript_files imports.js imports.wat)))

(rule
 (alias runtest)
 (enabled_if %{bin-available:node})
 (action
  (run node %{dep:./example.bc.js})))

(rule
 (alias runtest-wasm)
 (enabled_if %{bin-available:node})
 (action
  (run node %{dep:./example.bc.wasm.js})))


================================================
FILE: node-test/runtime_primitives/example.ml
================================================
open Bindings

let initial_content = "Hello, Node.js!"
let appended_line = "\nAppending a new line."
let encoding = "utf-8"
let filename = "example.txt"

let run () =
  let file = Path.join ["."; filename] in

  Fs.write_file_sync file initial_content;

  let content = Fs.read_file_sync file ~encoding in
  if content <> initial_content then
    failwith "Unexpected initial content";
  log ("File content: " ^ content);

  let files = Fs.readdir_sync "." |> Array.to_list in
  if not (List.mem filename files) then
    failwith "example.txt missing from directory listing";
  log ("Files in current directory: " ^ String.concat ", " files);

  Fs.append_file_sync file appended_line;

  let updated = Fs.read_file_sync file ~encoding in
  if updated <> initial_content ^ appended_line then
    failwith "Append failed";
  log ("Updated content: " ^ updated);
  log ("Path separator reported by Node: " ^ Path.separator);
  log ("Node.js version: " ^ node_version)


let () = run ()


================================================
FILE: node-test/runtime_primitives/imports.js
================================================
'use strict';

//Provides: node_path
var node_path = require('path');

//Provides: node_fs
var node_fs = require('fs');

//Provides: node_version
var node_version = require('process').version;

//Provides: node_console
var node_console = console.log;


================================================
FILE: node-test/runtime_primitives/imports.wat
================================================
(global (export "_node_path") (import "js" "node_path") anyref)
(global (export "_node_fs") (import "js" "node_fs") anyref)
(global (export "_node_version") (import "js" "node_version") anyref)
(global (export "_node_console") (import "js" "node_console") anyref)


================================================
FILE: node-test/test1/dune
================================================
(executable
 (name test)
 (libraries ojs node)
 (preprocess
  (pps gen_js_api.ppx))
 (modes js wasm)
 (js_of_ocaml
  (javascript_files recursive.js))
 (wasm_of_ocaml
  (javascript_files recursive.js)))

(rule
 (targets recursive.ml)
 (deps recursive.mli)
 (action
  (run gen_js_api %{deps})))

(rule
 (alias runtest)
 (enabled_if %{bin-available:node})
 (action
  (run node %{dep:./test.bc.js})))

(rule
 (alias runtest-wasm)
 (enabled_if %{bin-available:node})
 (action
  (run node %{dep:./test.bc.wasm.js})))


================================================
FILE: node-test/test1/recursive.js
================================================

var Foo = /*#__PURE__*/function () {
  "use strict";

  function Foo(name) {
    this.name = name;
  }

  var _proto = Foo.prototype;

  _proto.describe = function describe() {
    return "Foo:".concat(this.name);
  };

  _proto.toBar = function toBar() {
    return new Bar(this.name);
  };

  return Foo;
}();


var Bar = /*#__PURE__*/function () {
  "use strict";

  function Bar(name) {
    this.name = name;
  }

  var _proto2 = Bar.prototype;

  _proto2.describe = function describe() {
    return "Bar:".concat(this.name);
  };

  _proto2.toFoo = function toFoo() {
    return new Foo(this.name);
  };

  return Bar;
}();

globalThis.Foo = Foo
globalThis.Bar = Bar


================================================
FILE: node-test/test1/recursive.mli
================================================
module [@js.scope "Foo"] rec Foo : sig
  type t = private Ojs.t
  val t_of_js: Ojs.t -> t
  val t_to_js: t -> Ojs.t
  val create: string -> t [@@js.create]
  val describe: t -> string [@@js.call "describe"]
  val to_bar: t -> Bar.t [@@js.call "toBar"]
end

and [@js.scope "Bar"] Bar : sig
  type t = private Ojs.t
  val t_of_js: Ojs.t -> t
  val t_to_js: t -> Ojs.t
  val create: string -> t [@@js.create]
  val describe: t -> string [@@js.call "describe"]
  val to_foo: t -> Foo.t [@@js.call "toFoo"]
end


================================================
FILE: node-test/test1/test.ml
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

[@@@ocaml.warning "-32-34"]

open Node

let check_node_version version =
  let major_version = function
    | Some s when String.length s > 0 && s.[0] = 'v' ->
        begin match
          String.sub s 1 (String.length s - 1)
          |> String.split_on_char '.'
        with
        | [] -> None
        | hd :: _ -> int_of_string_opt hd
        end
    | _ -> None
  in
  if Option.value ~default:(-1) (major_version Process.version) < version then
    begin
      Printf.eprintf "[WARNING] Ignoring test: it requires Node > %d; please upgrade (current version %s)" version
        (Option.value ~default:"???" Process.version);
      exit 0
    end

let () =
  check_node_version 18

(** Buffer **)

let caml_from_set s =
  let len = String.length s in
  let buf = Buffer.alloc len in
  String.iteri (fun k x ->
      Buffer.set buf k (Char.code x)
    ) s;
  buf

let caml_from_write s =
  let len = String.length s in
  let buf = Buffer.alloc len in
  let written = Buffer.write buf s in
  assert (written = len);
  buf

let assert_equal_buffer b1 b2 =
  let len1 = Buffer.length b1 in
  let len2 = Buffer.length b2 in
  assert (len1 = len2);
  for k = 0 to len1 -1 do
    assert (Buffer.get b1 k = Buffer.get b2 k)
  done

let copy src =
  let len = Buffer.length src in
  let dst = Buffer.alloc len in
  let written =
    Buffer.copy src ~dst ~start:0 ~dst_start:0 ~dst_end:len
  in
  assert (len = written);
  dst

let () =
  let test = "test" in
  let native = Buffer.from test in
  let from_set = caml_from_set test in
  let from_write = caml_from_write test in
  let from_copy = copy native in
  assert_equal_buffer native from_set;
  assert_equal_buffer native from_write;
  assert_equal_buffer native from_copy

(** Process **)

let () =
  Container.StringMap.iter
    (fun key value ->
       assert (Sys.getenv key = value)
    )
    Process.env

let uncaught_handler p =
  let open Promise in
  catch p (fun error ->
      Printf.eprintf "Uncaught exception: %s\n" (Printexc.to_string (Obj.magic error));
      exit 1
    )

(** FileSystem **)

let root : unit Promise.t =
  let open Promise in
  uncaught_handler
    begin
      let* contents = Fs.readdir "."
      and+ contents' = Fs.readdir "." in
      List.iter2 (fun x y ->
          assert (x = y)) contents contents';
      return ()
    end

(*** Index signature **)

include [%js:
  module ArrayLike (K : Ojs.T) : sig
    type t = private Ojs.t
    val t_to_js: t -> Ojs.t
    val t_of_js: Ojs.t -> t

    val create: unit -> t [@@js.builder]
    val get: t -> int -> K.t option [@@js.index_get]
    val set: t -> int -> K.t -> unit [@@js.index_set]
  end

  module MapLike (K : Ojs.T) : sig
    type t = private Ojs.t
    val t_to_js: t -> Ojs.t
    val t_of_js: Ojs.t -> t

    val create: unit -> t [@@js.builder]
    val get: t -> string -> K.t option [@@js.index_get]
    val set: t -> string -> K.t -> unit [@@js.index_set]
  end

  module Symbol : sig
    type t = private Ojs.t
    val t_to_js: t -> Ojs.t
    val t_of_js: Ojs.t -> t

    val fresh: unit -> t [@@js.global "Symbol"]
  end

  module SymbolMap (K : Ojs.T) : sig
    type t = private Ojs.t
    val t_to_js: t -> Ojs.t
    val t_of_js: Ojs.t -> t

    val create: unit -> t [@@js.builder]
    val get: t -> Symbol.t -> K.t option [@@js.index_get]
    val set: t -> Symbol.t -> K.t -> unit [@@js.index_set]
  end

]

let () =
  let module M = MapLike([%js: type t = string val t_to_js: t -> Ojs.t val t_of_js: Ojs.t -> t]) in
  let map_str = M.create () in
  M.set map_str "foo" "bar";
  assert (M.get map_str "foo" = Some "bar");
  M.set map_str "baz" "boo";
  assert (M.get map_str "baz" = Some "boo");

  let module A = ArrayLike([%js: type t = int val t_to_js: t -> Ojs.t val t_of_js: Ojs.t -> t]) in
  let map_int = A.create () in
  let len = 10 in
  for k = 0 to len - 1 do
    A.set map_int k k;
    assert (A.get map_int k = Some k);
    A.set map_int k (k * k);
    assert (A.get map_int k = Some (k * k));
  done;

  let module M = SymbolMap([%js: type t = string val t_to_js: t -> Ojs.t val t_of_js: Ojs.t -> t]) in
  let a = Symbol.fresh () in
  let b = Symbol.fresh () in
  let map_str = M.create () in
  M.set map_str a "bar";
  assert (M.get map_str a = Some "bar");
  M.set map_str b "boo";
  assert (M.get map_str b = Some "boo")


(*** Function signature **)

include [%js:
  module Concat : sig
    type t = private Ojs.t

    val t_to_js: t -> Ojs.t
    val t_of_js: Ojs.t -> t

    val apply: t -> (string list [@js.variadic]) -> string [@@js.apply]
  end

  module [@js.scope Imports.path] Path2 : sig
    val join: Concat.t [@@js.global "join"]
  end
]

let () =
  let args = ["foo"; "bar"; "baz"] in
  let res1 = Path.join args in
  let res2 = Concat.apply Path2.join args in
  assert (res1 = res2);
  ()

(*** Newable function *)

include [%js:
  module Date: sig
    type t = private Ojs.t
    val getUTCFullYear: t -> float [@@js.call "getUTCFullYear"]
    val getUTCMonth: t -> float [@@js.call "getUTCMonth"]
    val getUTCDate: t -> float [@@js.call "getUTCDate"]
  end

  module DateConstructor: sig
    type t = private Ojs.t
    val utc:
      t ->
      year:int -> month:int -> ?date:int ->
      ?hours:int -> ?minutes:int -> ?seconds:int ->
      ?ms:int -> unit -> float [@@js.call "UTC"]
    val new_:
      t -> float -> Date.t [@@js.apply_newable]
  end

  val date: DateConstructor.t [@@js.global "Date"]
]

let () =
  let d =
    DateConstructor.new_ date
      (DateConstructor.utc date ~year:1999 ~month:11 ~date:31 ())
  in
  assert (int_of_float (Date.getUTCFullYear d) == 1999);
  assert (int_of_float (Date.getUTCMonth d) == 11);
  assert (int_of_float (Date.getUTCDate d) == 31);
  ()

(** Arrays **)
let () =
  let open Arrays.StringArray in
  let a = create () in
  for k = 0 to 10 do
    push a (string_of_int k);
  done;
  let s = join a "," in
  List.iteri (fun k x ->
      assert (string_of_int k = x)
    ) (String.split_on_char ',' s)

(** Invoking a global object **)
(** https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/Number **)
let () =
  let check (a: Number.t) (b: float) =
    assert (Ojs.instance_of (a :> Ojs.t) ~constr:(Number.number :> Ojs.t));
    assert (not (Ojs.instance_of (Ojs.float_to_js b) ~constr:(Number.number :> Ojs.t)));
    assert (Number.valueOf a = b);
    ()
  in
  let s = Ojs.string_to_js "123" in
  check (Number.Scoped.create s) (Number.Scoped.invoke s);
  check (Number.Static.create Number.number s) (Number.Static.apply Number.number s);
  assert (Number.Scoped.max_value = Number.Static.max_value Number.number);
  ()

(** Using recursive modules **)
let () =
  let open Recursive in
  let fooA = Foo.create "A" in
  assert (Foo.describe fooA = "Foo:A");
  let barA = Foo.to_bar fooA in
  assert (Bar.describe barA = "Bar:A");
  let fooA' = Bar.to_foo barA in
  assert (Foo.describe fooA' = "Foo:A");
  ()

(** Using first class modules **)
include [%js:
  val to_string: (module[@js] Ojs.T with type t = 'a) -> 'a -> string [@@js.call "toString"]
]
let () =
  let check (type a) (module A : Ojs.T with type t = a) (value: a) (expected: string) =
    let str = to_string (module A) value in
    assert (str = expected)
  in
  check (module Ojs.Int) 42 "42";
  check (module Ojs.Float) 4.2 "4.2";
  check (module Ojs.String) "hello" "hello";
  check (module Ojs.List(Ojs.Int)) [4;2] "4,2";
  check (module Ojs.List(Ojs.String)) ["hello"; "world"] "hello,world";
  ()
let () =
  let open Arrays.JsArray2 in
  let a = create () in
  for k = 0 to 10 do
    push (module Ojs.String) a (string_of_int k);
  done;

  let sa = join a "," in
  List.iteri (fun k x ->
      assert (string_of_int k = x)
    ) (String.split_on_char ',' sa);

  let b =
    let orig = List.init 11 string_of_int in
    create' (module Ojs.String) orig
  in
  let sb = join b "," in
  assert (sa = sb);

  assert (get (module Ojs.String) a 0 = Some "0");
  set (module Ojs.String) a 1 "foo";
  assert (get (module Ojs.String) a 1 = Some "foo");
  ()


================================================
FILE: ojs.opam
================================================
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "1.1.7"
synopsis: "Runtime Library for gen_js_api generated libraries"
description: "To be used in conjunction with gen_js_api"
maintainer: ["Alain Frisch <alain.frisch@lexifi.com>"]
authors: [
  "Alain Frisch <alain.frisch@lexifi.com>"
  "Sebastien Briais <sebastien.briais@lexifi.com>"
]
license: "MIT"
homepage: "https://github.com/LexiFi/gen_js_api"
bug-reports: "https://github.com/LexiFi/gen_js_api/issues"
depends: [
  "dune" {>= "3.17"}
  "ocaml" {>= "4.13"}
  "js_of_ocaml-compiler" {>= "6.3.0"}
  "odoc" {with-doc}
]
dev-repo: "git+https://github.com/LexiFi/gen_js_api.git"
build: [
  ["dune" "subst"] {dev}
  ["dune" "build" "-p" name "-j" jobs "@install" "@doc" {with-doc}]
]


================================================
FILE: ojs.opam.template
================================================
build: [
  ["dune" "subst"] {dev}
  ["dune" "build" "-p" name "-j" jobs "@install" "@doc" {with-doc}]
]


================================================
FILE: ppx-driver/dune
================================================
(library
 (name gen_js_api_ppx_driver)
 (public_name gen_js_api.ppx)
 (synopsis "Syntactic support for gen_js_api")
 (libraries gen_js_api.lib ppxlib.ast ppxlib)
 (kind ppx_rewriter)
 (ppx_runtime_libraries ojs)
 (preprocess no_preprocessing))


================================================
FILE: ppx-driver/gen_js_api_ppx_driver.ml
================================================
let check_attributes_with_ppxlib = false
let check_locations_with_ppxlib = false

let () =
  if check_attributes_with_ppxlib
  then (
    Ppxlib.Driver.enable_checks ();
    Gen_js_api_ppx.check_attribute := false
  );
  if check_locations_with_ppxlib
  then (
    Ppxlib.Driver.enable_location_check ()
  );
  let mapper_for_sig =
    Gen_js_api_ppx.mark_attributes_as_used
  in
  let mapper_for_str =
    Gen_js_api_ppx.mark_attributes_as_used
  in
  let module_expr_ext =
    let rewriter ~loc ~path:_ si =
      Gen_js_api_ppx.module_expr_rewriter ~loc ~attrs:[] si
    in
    Ppxlib.Extension.declare "js"
      Ppxlib.Extension.Context.Module_expr
      Ppxlib.(Ast_pattern.psig Ast_pattern.__)
      rewriter
    |> Ppxlib.Context_free.Rule.extension
  in
  let ext_to =
    let rewriter ~loc ~path:_ core_type =
      Gen_js_api_ppx.js_to_rewriter ~loc core_type
    in
    Ppxlib.Extension.declare "js.to"
      Ppxlib.Extension.Context.Expression
      Ppxlib.(Ast_pattern.ptyp Ast_pattern.__)
      rewriter
    |> Ppxlib.Context_free.Rule.extension
  in
  let ext_of =
    let rewriter ~loc ~path:_ core_type =
      Gen_js_api_ppx.js_of_rewriter ~loc core_type
    in
    Ppxlib.Extension.declare "js.of"
      Ppxlib.Extension.Context.Expression
      Ppxlib.(Ast_pattern.ptyp Ast_pattern.__)
      rewriter
    |> Ppxlib.Context_free.Rule.extension
  in
  let attr_typ =
    let rewriter ~ctxt (rec_flag : Ppxlib.Asttypes.rec_flag) tdl _ =
      Gen_js_api_ppx.type_decl_rewriter
        ~loc:(Ppxlib.Expansion_context.Deriver.derived_item_loc ctxt)
        rec_flag tdl
    in
    Ppxlib.Context_free.Rule.attr_str_type_decl
      (Ppxlib.Attribute.declare "js"
         Ppxlib.Attribute.Context.type_declaration
         Ppxlib.(Ast_pattern.pstr Ast_pattern.nil) ())
      rewriter
  in
  Ppxlib.Driver.register_transformation
    "gen_js_api"
    ~rules:[module_expr_ext; ext_of; ext_to; attr_typ ]
    ~impl:(mapper_for_str # structure)
    ~intf:(mapper_for_sig # signature)


================================================
FILE: ppx-lib/dune
================================================
(library
 (name gen_js_api_ppx)
 (public_name gen_js_api.lib)
 (libraries compiler-libs.common ppxlib)
 (ppx_runtime_libraries ojs)
 (preprocess no_preprocessing))


================================================
FILE: ppx-lib/gen_js_api_ppx.ml
================================================
(* The gen_js_api is released under the terms of an MIT-like license.     *)
(* See the attached LICENSE file.                                         *)
(* Copyright 2015 by LexiFi.                                              *)

open Ppxlib

open Asttypes
open Parsetree
open Longident
open Ast_helper
open Location

let mkloc txt loc =
  { txt; loc }

let mknoloc txt =
  mkloc txt !Ast_helper.default_loc

(** Errors *)

type error =
  | Expression_expected
  | Identifier_expected
  | Structure_expected
  | Invalid_expression
  | Multiple_binding_declarations
  | Binding_type_mismatch
  | Cannot_parse_type
  | Cannot_parse_sigitem
  | Cannot_parse_classdecl
  | Cannot_parse_classfield
  | Implicit_name of string
  | Not_supported_here of string
  | Record_expected of string
  | Record_constructor_in_union
  | Unknown_union_method
  | Non_constant_constructor_in_enum
  | Multiple_default_case
  | Duplicate_case_value of location * location
  | Invalid_variadic_type_arg
  | No_input
  | Multiple_inputs
  | Unlabelled_argument_in_builder
  | Spurious_attribute of label
  | Sum_kind_args
  | Union_without_discriminator
  | Contravariant_type_parameter of string
  | Cannot_set_runtime_value of string

exception Error of Location.t * error

let is_ascii s =
  let exception Break in
  try
    String.iter (fun c -> if Char.code c > 127 then raise Break) s;
    true
  with Break -> false

let check_attribute = ref true
let used_attributes_tbl = Hashtbl.create 16

(* [merlin_hide] tells merlin to not look at a node, or at any of its
   descendants.  *)
let merlin_hide =
  { attr_name = { txt = "merlin.hide"; loc = Location.none }
  ; attr_payload = PStr []
  ; attr_loc = Location.none
  }

let register_loc attr =
  Ppxlib.Attribute.mark_as_handled_manually attr;
  Hashtbl.replace used_attributes_tbl attr.attr_name.loc ()

let is_registered_loc loc = Hashtbl.mem used_attributes_tbl loc

let error loc err = raise (Error (loc, err))

let filter_attr_name key attr =
  if attr.attr_name.txt = key then begin
    register_loc attr;
    true
  end else false

let filter_extension key name = name.txt = key

let has_attribute key attrs = List.exists (filter_attr_name key) attrs

let get_attribute key attrs =
  match List.find (filter_attr_name key) attrs with
  | exception Not_found -> None
  | attr -> Some attr

let unoption = function
  | Some x -> x
  | None -> assert false

let expr_of_stritem = function
  | {pstr_desc=Pstr_eval (e, _); _} -> e
  | p -> error p.pstr_loc Expression_expected

let expr_of_payload {attr_loc; attr_payload; _} =
  match attr_payload with
  | PStr [x] -> expr_of_stritem x
  | _ -> error attr_loc Expression_expected

let str_of_payload {attr_loc; attr_payload; _} =
  match attr_payload with
  | PStr x -> x
  | _ -> error attr_loc Structure_expected

let id_of_expr = function
  | {pexp_desc=Pexp_constant (Pconst_string (s, _, _)); _} -> s
  | e -> error e.pexp_loc Identifier_expected

let get_expr_attribute key attrs =
  match get_attribute key attrs with
  | None -> None
  | Some payload -> Some (expr_of_payload payload)

let get_string_attribute key attrs =
  match get_attribute key attrs with
  | None -> None
  | Some payload -> Some (id_of_expr (expr_of_payload payload))

let get_string_attribute_default key default attrs =
  match get_attribute key attrs with
  | None -> default
  | Some payload -> payload.attr_loc, id_of_expr (expr_of_payload payload)

let print_error ppf = function
  | Expression_expected ->
      Format.fprintf ppf "Expression expected"
  | Structure_expected ->
      Format.fprintf ppf "Structure expected"
  | Identifier_expected ->
      Format.fprintf ppf "String literal expected"
  | Invalid_expression ->
      Format.fprintf ppf "Invalid expression"
  | Multiple_binding_declarations ->
      Format.fprintf ppf "Multiple binding declarations"
  | Binding_type_mismatch ->
      Format.fprintf ppf "Binding declaration and type are not compatible"
  | Cannot_parse_type ->
      Format.fprintf ppf "Cannot parse type"
  | Cannot_parse_sigitem ->
      Format.fprintf ppf "Cannot parse signature item"
  | Cannot_parse_classdecl ->
      Format.fprintf ppf "Cannot parse class declaration"
  | Cannot_parse_classfield ->
      Format.fprintf ppf "Cannot parse class field"
  | Implicit_name prefix ->
      Format.fprintf ppf "Implicit name must start with '%s' and cannot be empty" prefix
  | Not_supported_here msg ->
      Format.fprintf ppf "%s not supported in this context" msg
  | Non_constant_constructor_in_enum ->
      Format.fprintf ppf "Constructors in enums cannot take arguments"
  | Multiple_default_case ->
      Format.fprintf ppf "At most one default constructor is supported in variants"
  | Duplicate_case_value (loc1, loc2)  ->
      let line1, line2 = loc1.loc_start.pos_lnum, loc2.loc_start.pos_lnum in
      let line1, line2 = if line1 < line2 then line1, line2 else line2, line1 in
      Format.fprintf ppf "This case value is used twice at lines %d and %d" line1 line2
  | Invalid_variadic_type_arg ->
      Format.fprintf ppf "A variadic function argument must be of type list"
  | No_input ->
      Format.fprintf ppf "An input file must be provided"
  | Multiple_inputs ->
      Format.fprintf ppf "A single input file must be provided"
  | Unlabelled_argument_in_builder ->
      Format.fprintf ppf "Arguments of builder must be named"
  | Spurious_attribute label ->
      Format.fprintf ppf "Spurious %s attribute" label
  | Sum_kind_args ->
      Format.fprintf ppf "Incompatible label name for 'kind' and constructor arguments."
  | Record_constructor_in_union ->
      Format.fprintf ppf "Constructors in unions must not be an inline record."
  | Unknown_union_method ->
      Format.fprintf ppf "Unknown method to discriminate unions."
  | Union_without_discriminator ->
      Format.fprintf ppf "js.union without way to discriminate values."
  | Contravariant_type_parameter label ->
      Format.fprintf ppf "Contravariant type parameter '%s is not allowed." label
  | Record_expected shape ->
      Format.fprintf ppf "Record %s expected." shape
  | Cannot_set_runtime_value name ->
      Format.fprintf ppf "Cannot set runtime value '%s'." name

let () =
  Location.Error.register_error_of_exn
    (function
      | Error (loc, err) ->
          let createf ~loc fmt =
            Format.kasprintf
              (fun str -> Location.Error.make ~loc ~sub:[] str) fmt
          in
          Some (createf ~loc "%a" print_error err)
      | _ -> None
    )

(*
let show_attrs attrs =
  prerr_endline "===========";
  prerr_endline "attributes:";
  List.iter (fun ({txt; loc = _}, _) -> prerr_endline txt) attrs
*)

let js_name ~global_attrs ?(capitalize = false) name =
  if has_attribute "js.verbatim_names" global_attrs then
    if capitalize then String.capitalize_ascii name
    else name
  else
    let n = String.length name in
    let buf = Buffer.create n in
    let capitalize = ref capitalize in
    for i = 0 to n-1 do
      let c = name.[i] in
      if c = '_' then capitalize := true
      else if !capitalize then begin
        Buffer.add_char buf (Char.uppercase_ascii c);
        capitalize := false
      end else Buffer.add_char buf c
    done;
    Buffer.contents buf

let get_js_constr ~global_attrs name attributes =
  match get_attribute "js" attributes with
  | None -> `String (js_name ~global_attrs name)
  | Some payload ->
      begin match (expr_of_payload payload).pexp_desc with
      | Pexp_constant (Pconst_string (s, _, _)) -> `String s
      | Pexp_constant (Pconst_integer (n, _)) -> `Int n
      | Pexp_constant (Pconst_float (f, _)) -> `Float f
      | Pexp_construct (ident_loc, _) ->
          begin match ident_loc.txt with
          | Lident "true"  -> `Bool true
          | Lident "false" -> `Bool false
          | _ -> error ident_loc.loc Invalid_expression
          end
      | _ -> error payload.attr_loc Invalid_expression
      end

(** AST *)

type typ =
  | Arrow of arrow_params
  | Unit of Location.t
  | Js
  | Name of string * typ list
  | Variant of { location: Location.t;
                 global_attrs:attributes;
                 attributes:attributes;
                 constrs:constructor list }
  | Tuple of typ list
  | Typ_var of string
  | Packaged_type of { local_name:  string; (* `a` specified by `(type a)`*)
                       module_name: string  (* `A` as in `(module A : Ojs.T with type t = a)` *) }

and lab =
  | Arg
  | Lab of {ml: string}
  | Opt of {ml: string; def: Parsetree.expression option}

and arg =
  {
    lab: lab;
    att: attributes;
    typ: typ;
  }

and arrow_params =
  {
    ty_args: arg list;
    ty_vararg: arg option;
    unit_arg: bool;
    ty_res: typ;
  }

and constructor_arg =
  | Constant
  | Unary of typ
  | Nary of typ list
  | Record of (Location.t * lid * string * typ) list

and constructor =
  {
    mlconstr: string;
    arg: constructor_arg;
    attributes: attributes;
    location: Location.t;
  }

let arg_label = function
  | Arg -> Nolabel
  | Lab {ml; _} -> Labelled ml
  | Opt {ml; _} -> Optional ml

type apply_type =
  | Function    (* f(..) *)
  | NewableFunction (* new f(..) *)

type valdef =
  | Cast
  | Ignore
  | PropGet of string
  | PropSet of string
  | IndexGet
  | IndexSet
  | MethCall of string
  | Apply of apply_type
  | Invoke
  | Global of string
  | New of string option
  | Builder of attributes
  | Auto of valdef

let rec string_of_valdef = function
  | Cast -> "js.cast"
  | Ignore -> "js.ignore"
  | PropGet _ -> "js.get"
  | PropSet _ -> "js.set"
  | IndexGet -> "js.index_get"
  | IndexSet -> "js.index_set"
  | MethCall _ -> "js.call"
  | Apply Function -> "js.apply"
  | Apply NewableFunction -> "js.apply_newable"
  | Invoke -> "js.invoke"
  | Global _ -> "js.global"
  | New None -> "js.create"
  | New (Some _) -> "js.new"
  | Builder _ -> "js.builder"
  | Auto valdef -> string_of_valdef valdef

let auto_deprecation_attribute loc valdef =
  let message =
    Printf.sprintf
      "Heuristic for automatic binding is deprecated; please add the '@%s' attribute."
      (string_of_valdef valdef)
  in
  attribute_of_warning loc message

type methoddef =
  | Getter of string
  | Setter of string
  | IndexGetter
  | IndexSetter
  | MethodCall of string
  | ApplyAsFunction of apply_type

type method_decl =
  {
    method_name: string;
    method_typ: typ;
    method_def: methoddef;
    method_loc: Location.t;
    method_attrs: attributes
  }

type class_field =
  | Method of method_decl
  | Inherit of Longident.t Location.loc

type classdecl =
  | Declaration of { class_name: string; class_fields: class_field list }
  | Constructor of { class_name: string; js_class_name: string; class_arrow: arrow_params }

type decl =
  | Module of functor_parameter list * string * decl list
  | RecModule of (module_type * functor_parameter list * string * decl list) list
  | ModuleAlias of string * Longident.t Location.loc
  | Type of rec_flag * Parsetree.type_declaration list * attributes
  | Val of { name:string;
             ty: typ;
             decl: valdef;
             loc: Location.t;
             packages: (string * string) list; (** reversed order, (local_name, module_name) *)
             global_attrs: attributes }
  | Class of classdecl list
  | Implem of Parsetree.structure
  | Open of Parsetree.open_description
  | Include of Parsetree.module_expr Parsetree.include_infos

(** Parsing *)

let local_type_of_type_var label =
  "__"^label


let neg_variance = function
  | -1 -> 1
  | 0 | 1 -> -1
  | _ -> invalid_arg "neg_variance"

let no_attributes attributes =
  List.iter (fun attr ->
      ignore (filter_attr_name "js.dummy" attr)
    ) attributes;
  attributes = []

type type_context =
  {
    type_params: string list;
    packages: (string * string) list; (** reversed order, (local_name, module_name) *)
  }

let empty_type_context = { type_params = []; packages = [] }

let rec parse_arg ~variance (ctx: type_context) lab ~global_attrs ty =
  let lab =
    match lab with
    | Nolabel -> Arg
    | Labelled ml -> Lab {ml}
    | Optional ml ->
        Opt {ml; def=get_expr_attribute "js.default" ty.ptyp_attributes}
  in
  {
    lab;
    att=ty.ptyp_attributes;
    typ = parse_typ ~variance:(neg_variance variance) ctx ~global_attrs ty;
  }

and parse_typ ~variance ctx ~global_attrs ty =
  match ty.ptyp_desc with
  | Ptyp_arrow (lab, t1, t2) when has_attribute "js.variadic" t1.ptyp_attributes ->
      begin match parse_arg ~variance ctx lab ~global_attrs t1 with
      | {lab; att; typ=Name ("list", [typ])} ->
          let ty_vararg = Some {lab; att; typ} in
          begin match parse_typ ~variance ctx ~global_attrs t2 with
          | Arrow ({ty_args = []; ty_vararg = None; unit_arg = _; ty_res = _} as params) when no_attributes t2.ptyp_attributes ->
              Arrow {params with ty_vararg}
          | Arrow _ when t2.ptyp_attributes = [] -> error ty.ptyp_loc Cannot_parse_type
          | tres -> Arrow {ty_args = []; ty_vararg; unit_arg = false; ty_res = tres}
          end
      | _ -> error t1.ptyp_loc Invalid_variadic_type_arg
      end
  | Ptyp_arrow (lab, t1, t2) ->
      let t1 = parse_arg ~variance ctx lab ~global_attrs t1 in
      begin match parse_typ ~variance ctx ~global_attrs t2 with
      | Arrow ({ty_args; ty_vararg = _; unit_arg = _; ty_res = _} as params) when no_attributes t2.ptyp_attributes -> Arrow {params with ty_args = t1 :: ty_args}
      | tres ->
          begin match t1 with
          | {lab=Arg; att=[]; typ=Unit _} -> Arrow {ty_args = []; ty_vararg = None; unit_arg = true; ty_res = tres}
          | _ -> Arrow {ty_args = [t1]; ty_vararg = None; unit_arg = false; ty_res = tres}
          end
      end
  | Ptyp_constr ({txt = lid; loc = _}, tl) ->
      begin match String.concat "." (Longident.flatten_exn lid), tl with
      | "unit", [] -> Unit ty.ptyp_loc
      | "Ojs.t", [] -> Js
      | s, tl -> Name (s, List.map (parse_typ ~variance ctx ~global_attrs) tl)
      end
  | Ptyp_variant (rows, Closed, None) ->
      let location = ty.ptyp_loc in
      let prepare_row = function
        | {prf_desc = Rtag ({txt = mlconstr; _}, true, []); prf_attributes = attributes; prf_loc = location} ->
            { mlconstr; arg = Constant; attributes; location }
        | {prf_desc = Rtag ({txt = mlconstr; _}, false, [typ]); prf_attributes = attributes; prf_loc = location} ->
            begin match parse_typ ~variance ctx ~global_attrs typ with
            | Tuple typs -> { mlconstr; arg = Nary typs; attributes; location }
            | typ -> { mlconstr; arg = Unary typ; attributes; location }
            end
        | _ -> error location Cannot_parse_type
      in
      Variant {location; global_attrs; attributes = ty.ptyp_attributes; constrs = List.map prepare_row rows}

  | Ptyp_tuple typs ->
      let typs = List.map (parse_typ ~variance ctx ~global_attrs) typs in
      Tuple typs

  | Ptyp_var label ->
      if List.mem label ctx.type_params then
        if variance < 0 then
          error ty.ptyp_loc (Contravariant_type_parameter label)
        else
          Name (local_type_of_type_var label, [])
      else
        begin match List.assoc_opt label ctx.packages with
        | Some module_name -> Packaged_type { local_name = label; module_name }
        | None -> Typ_var label
        end

  | _ ->
      error ty.ptyp_loc Cannot_parse_type

let parse_typ = parse_typ ~variance:0

let check_prefix ~prefix s =
  let l = String.length prefix in
  if l <= String.length s && String.sub s 0 l = prefix
  then
    Some (String.sub s l (String.length s - l))
  else
    None

let has_prefix ~prefix s = check_prefix ~prefix s <> None

let drop_prefix ~prefix s =
  match check_prefix ~prefix s with
  | Some x -> x
  | None -> assert false


let check_suffix ~suffix s =
  let l = String.length suffix in
  if l <= String.length s && String.sub s (String.length s - l) l = suffix
  then
    Some (String.sub s 0 (String.length s - l))
  else
    None

let rec choose f = function
  | [] -> []
  | x :: xs ->
      begin match f x with
      | None -> choose f xs
      | Some y -> y :: choose f xs
      end

let derived_from_type s ty =
  match ty with
  | Arrow {ty_args; ty_vararg = None; unit_arg = false; ty_res = Js} ->
      begin match List.rev ty_args with
      | {lab=Arg; att=_; typ=Name (t, _);} :: _ -> check_suffix ~suffix:"_to_js" s = Some t
      | _ -> false
      end
  | Arrow {ty_res = Name (t, _); ty_vararg = None; unit_arg = false; ty_args } ->
      begin match List.rev ty_args with
      | {lab=Arg; att=_; typ= Js;} :: _ -> check_suffix ~suffix:"_of_js" s = Some t
      | _ -> false
      end
  | _ -> false

let auto ~global_attrs s ty =
  if derived_from_type s ty then
    Ignore
  else
    Auto begin match ty with
      | Arrow {ty_args = _; ty_vararg = None; unit_arg = _; ty_res = Name _} when s = "create" -> New None
      | Arrow {ty_args = _; ty_vararg = None; unit_arg = _; ty_res = Name _} when has_prefix ~prefix:"new_" s -> New (Some (js_name ~capitalize:true ~global_attrs (drop_prefix ~prefix:"new_" s)))
      | Arrow {ty_args = [_]; ty_vararg = None; unit_arg = false; ty_res = Unit _} when has_prefix ~prefix:"set_" s -> PropSet (js_name ~global_attrs (drop_prefix ~prefix:"set_" s))
      | Arrow {ty_args = [{lab=Arg; att=_; typ=Name _}; _; _]; ty_vararg = None; unit_arg = false; ty_res = Unit _} when s = "set" -> IndexSet
      | Arrow {ty_args = [{lab=Arg; att=_; typ=Name _}; _]; ty_vararg = None; unit_arg = false; ty_res = Unit _} when has_prefix ~prefix:"set_" s -> PropSet (js_name ~global_attrs (drop_prefix ~prefix:"set_" s))
      | Arrow {ty_args = [{lab=Arg; att=_; typ=Name _}]; ty_vararg = None; unit_arg = false; ty_res = Unit _} -> MethCall (js_name ~global_attrs s)
      | Arrow {ty_args = [{lab=Arg; att=_; typ=Name _}; _]; ty_vararg = None; unit_arg = false; ty_res = _} when s = "get" -> IndexGet
      | Arrow {ty_args = [{lab=Arg; att=_; typ=Name _}]; ty_vararg = None; unit_arg = false; ty_res = _} -> PropGet (js_name ~global_attrs s)
      | Arrow {ty_args = []; ty_vararg = None; unit_arg = true; ty_res = _} -> PropGet (js_name ~global_attrs s)
      | Arrow {ty_args = {lab=Arg; att=_; typ=Name _} :: _; ty_vararg = _; unit_arg = _; ty_res = _} when s = "apply" -> Apply Function
      | Arrow {ty_args = {lab=Arg; att=_; typ=Name _} :: _; ty_vararg = _; unit_arg = _; ty_res = _} -> MethCall (js_name ~global_attrs s)
      | _ -> Global (js_name ~global_attrs s)
    end

let auto_in_object ~global_attrs s typ =
  Auto begin match typ with
    | Arrow {ty_args = [{lab=Arg; att=_; typ=_}]; ty_vararg = None; unit_arg = false; ty_res = Unit _} when has_prefix ~prefix:"set_" s -> PropSet (js_name ~global_attrs (drop_prefix ~prefix:"set_" s))
    | Arrow {ty_args = [_]; ty_vararg = None; unit_arg = _; ty_res = _} when s = "get" -> IndexGet
    | Arrow {ty_args = [_; _]; ty_vararg = None; unit_arg = false; ty_res = Unit _} when s = "set" -> IndexSet
    | Arrow _ when s = "apply" -> Apply Function
    | Arrow _ -> MethCall (js_name ~global_attrs s)
    | Unit _ -> MethCall (js_name ~global_attrs s)
    | _ -> PropGet (js_name ~global_attrs s)
  end

let parse_attr ~global_attrs (s, loc, auto) attribute =
  let opt_name ?(prefix = "") ?(capitalize = false) () =
    match attribute.attr_payload with
    | PStr [] ->
        begin match check_prefix ~prefix s with
        | None | Some "" -> error loc (Implicit_name prefix)
        | Some s
Download .txt
gitextract_fdgla5ae/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       └── workflow.yml
├── .gitignore
├── .ocp-indent
├── CHANGES.md
├── CLASSES.md
├── IMPLGEN.md
├── INSTALL_AND_USE.md
├── LICENSE
├── LOW_LEVEL_BINDING.md
├── Makefile
├── NAMING.md
├── NODE_RUNTIME_BINDINGS.md
├── PPX.md
├── README.md
├── TODO.md
├── TYPES.md
├── VALUES.md
├── dune
├── dune-project
├── examples/
│   ├── calc/
│   │   ├── calc.html
│   │   ├── calc.ml
│   │   └── dune
│   ├── misc/
│   │   ├── dune
│   │   ├── jquery.mli
│   │   ├── js_date.mli
│   │   ├── js_str.mli
│   │   ├── test_jquery.html
│   │   └── test_jquery.ml
│   └── test/
│       ├── dune
│       ├── main.html
│       ├── main.ml
│       └── test_bindings.mli
├── gen_js_api.opam
├── lib/
│   ├── dune
│   ├── ojs.ml
│   ├── ojs.mli
│   ├── ojs_exn.ml
│   ├── ojs_exn.mli
│   ├── ojs_runtime.js
│   └── ojs_runtime_stubs.c
├── node-test/
│   ├── bindings/
│   │   ├── arrays.mli
│   │   ├── buffer.mli
│   │   ├── console.mli
│   │   ├── container.ml
│   │   ├── container.mli
│   │   ├── dune
│   │   ├── errors.mli
│   │   ├── expected/
│   │   │   ├── arrays.ml
│   │   │   ├── buffer.ml
│   │   │   ├── console.ml
│   │   │   ├── errors.ml
│   │   │   ├── fs.ml
│   │   │   ├── global.ml
│   │   │   ├── imports.ml
│   │   │   ├── number.ml
│   │   │   ├── path.ml
│   │   │   ├── process.ml
│   │   │   └── promise.ml
│   │   ├── fs.mli
│   │   ├── global.mli
│   │   ├── imports.js
│   │   ├── imports.mli
│   │   ├── imports.wat
│   │   ├── number.mli
│   │   ├── path.mli
│   │   ├── process.mli
│   │   └── promise.mli
│   ├── runtime_primitives/
│   │   ├── bindings.mli
│   │   ├── dune
│   │   ├── example.ml
│   │   ├── imports.js
│   │   └── imports.wat
│   └── test1/
│       ├── dune
│       ├── recursive.js
│       ├── recursive.mli
│       └── test.ml
├── ojs.opam
├── ojs.opam.template
├── ppx-driver/
│   ├── dune
│   └── gen_js_api_ppx_driver.ml
├── ppx-lib/
│   ├── dune
│   ├── gen_js_api_ppx.ml
│   └── gen_js_api_ppx.mli
├── ppx-standalone/
│   ├── dune
│   ├── gen_js_api.ml
│   └── gen_js_api.mli
└── ppx-test/
    ├── binding.mli
    ├── binding_automatic.mli
    ├── binding_explicitly_automatic.mli
    ├── binding_manual.mli
    ├── dune
    ├── expected/
    │   ├── binding.ml
    │   ├── binding_automatic.ml
    │   ├── extension.ml
    │   ├── first_class_modules.ml
    │   ├── issues.ml
    │   ├── issues_mli.ml
    │   ├── modules.ml
    │   ├── recursive_modules.ml
    │   ├── scoped.ml
    │   ├── types.ml
    │   └── union_and_enum.ml
    ├── extension.ml
    ├── first_class_modules.mli
    ├── issues.ml
    ├── issues_mli.mli
    ├── modules.mli
    ├── ppx/
    │   ├── dune
    │   └── main.ml
    ├── recursive_modules.mli
    ├── scoped.mli
    ├── types.ml
    └── union_and_enum.mli
Download .txt
SYMBOL INDEX (6 symbols across 3 files)

FILE: lib/ojs_runtime.js
  function caml_ojs_wrap_fun_arguments (line 3) | function caml_ojs_wrap_fun_arguments(f) {
  function caml_ojs_iterate_properties (line 11) | function caml_ojs_iterate_properties(o, f) {

FILE: lib/ojs_runtime_stubs.c
  function caml_ojs_wrap_fun_arguments (line 3) | void caml_ojs_wrap_fun_arguments () {
  function caml_ojs_iterate_properties (line 7) | void caml_ojs_iterate_properties () {

FILE: node-test/test1/recursive.js
  function Foo (line 5) | function Foo(name) {
  function Bar (line 26) | function Bar(name) {
Condensed preview — 114 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (381K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 111,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: daily\n"
  },
  {
    "path": ".github/workflows/workflow.yml",
    "chars": 1665,
    "preview": "name: Builds, tests & co\n\non:\n  - push\n  - pull_request\n\npermissions: read-all\n\njobs:\n  build:\n    strategy:\n      fail-"
  },
  {
    "path": ".gitignore",
    "chars": 61,
    "preview": "gen_js_api.install\nojs.install\n*.merlin\n_build\n_opam\n.vscode\n"
  },
  {
    "path": ".ocp-indent",
    "chars": 32,
    "preview": "match_clause=4\nstrict_with=auto\n"
  },
  {
    "path": "CHANGES.md",
    "chars": 3354,
    "preview": "Changelog\n=========\n\nUnreleased\n----------\n\n- Support for binding to js_of_ocaml runtime primitives via `@`-prefixed pay"
  },
  {
    "path": "CLASSES.md",
    "chars": 3748,
    "preview": "Class wrapping in gen_js_api\n============================\n\ngen_js_api can bind JavaScript objects into OCaml abstract ty"
  },
  {
    "path": "IMPLGEN.md",
    "chars": 3457,
    "preview": "gen_js_api: generate implementations from interfaces\n====================================================\n\nThe primary o"
  },
  {
    "path": "INSTALL_AND_USE.md",
    "chars": 2103,
    "preview": "gen_js_api: installation and usage instructions\n===============================================\n\n\nDependencies\n---------"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "The MIT License (MIT)\n\nCopyright 2015 by LexiFi.\n\nPermission is hereby granted, free of charge, to any person obtaining\n"
  },
  {
    "path": "LOW_LEVEL_BINDING.md",
    "chars": 2533,
    "preview": "gen_js_api: low-level binding to JavaScript\n===========================================\n\nThe code generated by gen_js_ap"
  },
  {
    "path": "Makefile",
    "chars": 872,
    "preview": "# The package gen_js_api is released under the terms of an MIT-like license.\n# See the attached LICENSE file.\n# Copyrigh"
  },
  {
    "path": "NAMING.md",
    "chars": 1044,
    "preview": "gen_js_api: default naming convention\n=====================================\n\nJavaScript names corresponding to bound com"
  },
  {
    "path": "NODE_RUNTIME_BINDINGS.md",
    "chars": 6188,
    "preview": "# Binding Node.js Modules with Runtime Primitives\n\nThis guide shows how to use the new runtime primitive support in `gen"
  },
  {
    "path": "PPX.md",
    "chars": 1647,
    "preview": "gen_js_api: ppx mode\n====================\n\nWhile the primary mode of operation for gen_js_api is to generate an\n.ml file"
  },
  {
    "path": "README.md",
    "chars": 3796,
    "preview": "gen_js_api: easy OCaml bindings for JavaScript libraries\n========================================================\n\n[![Bu"
  },
  {
    "path": "TODO.md",
    "chars": 2008,
    "preview": "TODO list for gen_js_api\n========================\n\n- Create reasonably complete bindings for JavaScript's stdlib\n  (stri"
  },
  {
    "path": "TYPES.md",
    "chars": 16549,
    "preview": "Types supported in gen_js_api\n=============================\n\nJS-able types\n-------------\n\nA JS-able type is an OCaml typ"
  },
  {
    "path": "VALUES.md",
    "chars": 16056,
    "preview": "Value bindings in gen_js_api\n============================\n\n\nSupported forms\n---------------\n\n- Method call:\n\n  ```ocaml\n"
  },
  {
    "path": "dune",
    "chars": 115,
    "preview": "(env\n (dev\n  (flags (:standard))))\n\n(deprecated_library_name\n (old_public_name gen_js_api)\n (new_public_name ojs))\n"
  },
  {
    "path": "dune-project",
    "chars": 1102,
    "preview": "(lang dune 3.17)\n(name gen_js_api)\n(version 1.1.7)\n\n(maintainers \"Alain Frisch <alain.frisch@lexifi.com>\")\n(authors\n \"Al"
  },
  {
    "path": "examples/calc/calc.html",
    "chars": 119,
    "preview": "<html>\n  <head>\n    <title>Calculator</title>\n  </head>\n  <body>\n    <script src=\"calc.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/calc/calc.ml",
    "chars": 4604,
    "preview": "module Element = [%js:\n  type t\n\n  val t_of_js: Ojs.t -> t\n\n  val append_child: t -> t -> unit [@@js.call]\n\n  val set_at"
  },
  {
    "path": "examples/calc/dune",
    "chars": 231,
    "preview": "(executables\n (names calc)\n (libraries ojs)\n (preprocess\n  (pps gen_js_api.ppx))\n (modes js))\n\n(rule\n (targets calc.js)\n"
  },
  {
    "path": "examples/misc/dune",
    "chars": 544,
    "preview": "(executables\n (names test_jquery)\n (libraries ojs)\n (preprocess\n  (pps gen_js_api.ppx))\n (modes js))\n\n(rule\n (targets jq"
  },
  {
    "path": "examples/misc/jquery.mli",
    "chars": 4852,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "examples/misc/js_date.mli",
    "chars": 2471,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "examples/misc/js_str.mli",
    "chars": 2332,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "examples/misc/test_jquery.html",
    "chars": 322,
    "preview": "<html>\n  <head>\n  </head>\n  <body>\n    <span class=\"tofill\">One</span>\n    <span class=\"tofill\">Two</span>\n    <div id=\""
  },
  {
    "path": "examples/misc/test_jquery.ml",
    "chars": 2281,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "examples/test/dune",
    "chars": 330,
    "preview": "(executables\n (names main)\n (libraries ojs)\n (preprocess\n  (pps gen_js_api.ppx))\n (modes js))\n\n(rule\n (targets test_bind"
  },
  {
    "path": "examples/test/main.html",
    "chars": 3067,
    "preview": "<html>\n  <head>\n  </head>\n  <body>\n    <div class=\"myClass\">Blabla</div>\n    <canvas id=\"canvas\" width=\"200\" height=\"200"
  },
  {
    "path": "examples/test/main.ml",
    "chars": 9697,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "examples/test/test_bindings.mli",
    "chars": 7916,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "gen_js_api.opam",
    "chars": 1224,
    "preview": "# This file is generated by dune, edit dune-project instead\nopam-version: \"2.0\"\nversion: \"1.1.7\"\nsynopsis: \"Easy OCaml b"
  },
  {
    "path": "lib/dune",
    "chars": 258,
    "preview": "(library\n (public_name ojs)\n (synopsis \"Runtime support for gen_js_api\")\n (libraries js_of_ocaml-compiler.runtime)\n (wra"
  },
  {
    "path": "lib/ojs.ml",
    "chars": 5085,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "lib/ojs.mli",
    "chars": 4784,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "lib/ojs_exn.ml",
    "chars": 763,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "lib/ojs_exn.mli",
    "chars": 402,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "lib/ojs_runtime.js",
    "chars": 399,
    "preview": "//Provides: caml_ojs_wrap_fun_arguments\n//Requires: caml_js_wrap_callback\nfunction caml_ojs_wrap_fun_arguments(f) {\n  re"
  },
  {
    "path": "lib/ojs_runtime_stubs.c",
    "chars": 317,
    "preview": "#include <stdlib.h>\n#include <stdio.h>\nvoid caml_ojs_wrap_fun_arguments () {\n  fprintf(stderr, \"Unimplemented JavaScript"
  },
  {
    "path": "node-test/bindings/arrays.mli",
    "chars": 1115,
    "preview": "module JsArray (E: Ojs.T): sig\n  type t\n  val t_to_js: t -> Ojs.t\n  val t_of_js: Ojs.t -> t\n\n  val create: unit -> t [@@"
  },
  {
    "path": "node-test/bindings/buffer.mli",
    "chars": 538,
    "preview": "[@@@js.scope \"Buffer\"]\n\ntype t = private Ojs.t\nval t_of_js: Ojs.t -> t\nval t_to_js: t -> Ojs.t\n\nval alloc: int -> t[@@js"
  },
  {
    "path": "node-test/bindings/console.mli",
    "chars": 268,
    "preview": "[@@@js.scope \"console\"]\n\nval log: 'a -> unit [@@js.global]\nval error: 'a -> unit [@@js.global]\n\nmodule T : sig\n  val log"
  },
  {
    "path": "node-test/bindings/container.ml",
    "chars": 352,
    "preview": "module StringMap = struct\n  include Map.Make(String)\n\n  let t_to_js ml2js l =\n    let o = Ojs.empty_obj () in\n    iter ("
  },
  {
    "path": "node-test/bindings/container.mli",
    "chars": 157,
    "preview": "module StringMap : sig\n  include Map.S with type key = string\n  val t_to_js: ('a -> Ojs.t) -> 'a t -> Ojs.t\n  val t_of_j"
  },
  {
    "path": "node-test/bindings/dune",
    "chars": 1951,
    "preview": "(library\n (name node)\n (synopsis \"Bindings\")\n (libraries ojs)\n (preprocess\n  (pps gen_js_api.ppx))\n (modes byte)\n (js_of"
  },
  {
    "path": "node-test/bindings/errors.mli",
    "chars": 342,
    "preview": "module [@js.scope] Error : sig\n  type t\n  val t_to_js: t -> Ojs.t\n  val t_of_js: Ojs.t -> t\n\n  val create: string -> t ["
  },
  {
    "path": "node-test/bindings/expected/arrays.ml",
    "chars": 3244,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule JsArray(E:Ojs.T) ="
  },
  {
    "path": "node-test/bindings/expected/buffer.ml",
    "chars": 1884,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\ntype t = Ojs.t\nlet rec t_"
  },
  {
    "path": "node-test/bindings/expected/console.ml",
    "chars": 975,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nlet log : 'a -> unit =\n  "
  },
  {
    "path": "node-test/bindings/expected/errors.ml",
    "chars": 1128,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule Error =\n  struct\n "
  },
  {
    "path": "node-test/bindings/expected/fs.ml",
    "chars": 4807,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule Dirent =\n  struct\n"
  },
  {
    "path": "node-test/bindings/expected/global.ml",
    "chars": 1173,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\ntype timeout_id = Ojs.t\nl"
  },
  {
    "path": "node-test/bindings/expected/imports.ml",
    "chars": 156,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nlet path : Ojs.t = Jsoo_r"
  },
  {
    "path": "node-test/bindings/expected/number.ml",
    "chars": 4892,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\ntype t = Ojs.t\nlet rec t_"
  },
  {
    "path": "node-test/bindings/expected/path.ml",
    "chars": 2267,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nlet sep : string = Ojs.st"
  },
  {
    "path": "node-test/bindings/expected/process.ml",
    "chars": 399,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nlet env : string Containe"
  },
  {
    "path": "node-test/bindings/expected/promise.ml",
    "chars": 2467,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule UntypedPromise =\n "
  },
  {
    "path": "node-test/bindings/fs.mli",
    "chars": 1311,
    "preview": "[@@@js.scope \"@node_fs.promises\"]\n\nmodule Dirent : sig\n  type t = Ojs.t\n  val t_of_js: Ojs.t -> t\n  val t_to_js: t -> Oj"
  },
  {
    "path": "node-test/bindings/global.mli",
    "chars": 450,
    "preview": "type timeout_id\nval timeout_id_to_js: timeout_id -> Ojs.t\nval timeout_id_of_js: Ojs.t -> timeout_id\n\ntype interval_id\nva"
  },
  {
    "path": "node-test/bindings/imports.js",
    "chars": 105,
    "preview": "//Provides: node_path\nvar node_path = require('path');\n\n//Provides: node_fs\nvar node_fs = require('fs');\n"
  },
  {
    "path": "node-test/bindings/imports.mli",
    "chars": 43,
    "preview": "val path: Ojs.t [@@js.global \"@node_path\"]\n"
  },
  {
    "path": "node-test/bindings/imports.wat",
    "chars": 125,
    "preview": "\n(global (export \"_node_path\") (import \"js\" \"node_path\") anyref)\n(global (export \"_node_fs\") (import \"js\" \"node_fs\") any"
  },
  {
    "path": "node-test/bindings/number.mli",
    "chars": 1238,
    "preview": "type t = private Ojs.t\n\nval toString: t -> ?radix:int -> unit -> float [@@js.call]\nval toFixed: t -> ?fractionDigits:int"
  },
  {
    "path": "node-test/bindings/path.mli",
    "chars": 466,
    "preview": "[@@@js.scope Imports.path]\n\nval sep: string [@@js.global]\nval dirname: string -> string [@@js.global]\nval extname: strin"
  },
  {
    "path": "node-test/bindings/process.mli",
    "chars": 118,
    "preview": "[@@@js.scope \"process\"]\n\nval env : string Container.StringMap.t [@@js.global]\nval version: string option [@@js.global]"
  },
  {
    "path": "node-test/bindings/promise.mli",
    "chars": 2391,
    "preview": "module UntypedPromise : sig\n\n  type t = private Ojs.t\n  val t_to_js: t -> Ojs.t\n  val t_of_js: Ojs.t -> t\n\n  [@@@js.stop"
  },
  {
    "path": "node-test/runtime_primitives/bindings.mli",
    "chars": 640,
    "preview": "module [@js.scope \"@node_fs\"] Fs : sig\n  val write_file_sync : string -> string -> unit [@@js.global \"writeFileSync\"]\n  "
  },
  {
    "path": "node-test/runtime_primitives/dune",
    "chars": 521,
    "preview": "(rule\n (targets bindings.ml)\n (deps bindings.mli)\n (action\n  (run gen_js_api %{deps})))\n\n(executable\n (name example)\n (l"
  },
  {
    "path": "node-test/runtime_primitives/example.ml",
    "chars": 984,
    "preview": "open Bindings\n\nlet initial_content = \"Hello, Node.js!\"\nlet appended_line = \"\\nAppending a new line.\"\nlet encoding = \"utf"
  },
  {
    "path": "node-test/runtime_primitives/imports.js",
    "chars": 251,
    "preview": "'use strict';\n\n//Provides: node_path\nvar node_path = require('path');\n\n//Provides: node_fs\nvar node_fs = require('fs');\n"
  },
  {
    "path": "node-test/runtime_primitives/imports.wat",
    "chars": 264,
    "preview": "(global (export \"_node_path\") (import \"js\" \"node_path\") anyref)\n(global (export \"_node_fs\") (import \"js\" \"node_fs\") anyr"
  },
  {
    "path": "node-test/test1/dune",
    "chars": 511,
    "preview": "(executable\n (name test)\n (libraries ojs node)\n (preprocess\n  (pps gen_js_api.ppx))\n (modes js wasm)\n (js_of_ocaml\n  (ja"
  },
  {
    "path": "node-test/test1/recursive.js",
    "chars": 673,
    "preview": "\nvar Foo = /*#__PURE__*/function () {\n  \"use strict\";\n\n  function Foo(name) {\n    this.name = name;\n  }\n\n  var _proto = "
  },
  {
    "path": "node-test/test1/recursive.mli",
    "chars": 506,
    "preview": "module [@js.scope \"Foo\"] rec Foo : sig\n  type t = private Ojs.t\n  val t_of_js: Ojs.t -> t\n  val t_to_js: t -> Ojs.t\n  va"
  },
  {
    "path": "node-test/test1/test.ml",
    "chars": 8233,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ojs.opam",
    "chars": 777,
    "preview": "# This file is generated by dune, edit dune-project instead\nopam-version: \"2.0\"\nversion: \"1.1.7\"\nsynopsis: \"Runtime Libr"
  },
  {
    "path": "ojs.opam.template",
    "chars": 104,
    "preview": "build: [\n  [\"dune\" \"subst\"] {dev}\n  [\"dune\" \"build\" \"-p\" name \"-j\" jobs \"@install\" \"@doc\" {with-doc}]\n]\n"
  },
  {
    "path": "ppx-driver/dune",
    "chars": 244,
    "preview": "(library\n (name gen_js_api_ppx_driver)\n (public_name gen_js_api.ppx)\n (synopsis \"Syntactic support for gen_js_api\")\n (li"
  },
  {
    "path": "ppx-driver/gen_js_api_ppx_driver.ml",
    "chars": 1995,
    "preview": "let check_attributes_with_ppxlib = false\nlet check_locations_with_ppxlib = false\n\nlet () =\n  if check_attributes_with_pp"
  },
  {
    "path": "ppx-lib/dune",
    "chars": 164,
    "preview": "(library\n (name gen_js_api_ppx)\n (public_name gen_js_api.lib)\n (libraries compiler-libs.common ppxlib)\n (ppx_runtime_lib"
  },
  {
    "path": "ppx-lib/gen_js_api_ppx.ml",
    "chars": 86991,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-lib/gen_js_api_ppx.mli",
    "chars": 732,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-standalone/dune",
    "chars": 233,
    "preview": "(executables\n (names gen_js_api)\n (public_names gen_js_api)\n (package gen_js_api)\n (libraries compiler-libs.common ppxli"
  },
  {
    "path": "ppx-standalone/gen_js_api.ml",
    "chars": 375,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-standalone/gen_js_api.mli",
    "chars": 295,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-test/binding.mli",
    "chars": 1561,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-test/binding_automatic.mli",
    "chars": 1051,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-test/binding_explicitly_automatic.mli",
    "chars": 1176,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-test/binding_manual.mli",
    "chars": 1419,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-test/dune",
    "chars": 3244,
    "preview": "(rule\n (targets extension.ml.result)\n (deps extension.ml)\n (action\n  (run ppx/main.exe --impl %{deps} -o %{targets})))\n\n"
  },
  {
    "path": "ppx-test/expected/binding.ml",
    "chars": 3470,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule M =\n  struct\n    t"
  },
  {
    "path": "ppx-test/expected/binding_automatic.ml",
    "chars": 5225,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\n[@@@warning \"-22\"]\nmodule"
  },
  {
    "path": "ppx-test/expected/extension.ml",
    "chars": 143,
    "preview": "let _ = Ojs.int_to_js\nlet _ =\n  fun (x2 : int -> int) ->\n    Ojs.fun_to_js 1\n      (fun (x3 : Ojs.t) -> Ojs.int_to_js (x"
  },
  {
    "path": "ppx-test/expected/first_class_modules.ml",
    "chars": 6957,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule Console =\n  struct"
  },
  {
    "path": "ppx-test/expected/issues.ml",
    "chars": 9740,
    "preview": "module Issue116 : sig type t end =\n  ((struct\n      [@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n   "
  },
  {
    "path": "ppx-test/expected/issues_mli.ml",
    "chars": 433,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule Issue144 =\n  struc"
  },
  {
    "path": "ppx-test/expected/modules.ml",
    "chars": 643,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule Event =\n  struct\n "
  },
  {
    "path": "ppx-test/expected/recursive_modules.ml",
    "chars": 1635,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\nmodule rec\n  Foo:sig\n    "
  },
  {
    "path": "ppx-test/expected/scoped.ml",
    "chars": 4040,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\n[@@@warning \"-22\"]\nmodule"
  },
  {
    "path": "ppx-test/expected/types.ml",
    "chars": 28401,
    "preview": "type 'a of_js = Ojs.t -> 'a\ntype 'a to_js = 'a -> Ojs.t\n[@@@ocaml.text \" JS-able types \"]\nlet _ : string of_js = Ojs.str"
  },
  {
    "path": "ppx-test/expected/union_and_enum.ml",
    "chars": 17678,
    "preview": "[@@@js.dummy \"!! This code has been generated by gen_js_api !!\"]\n[@@@ocaml.warning \"-7-32-39\"]\ntype enum_int =\n  | Enum_"
  },
  {
    "path": "ppx-test/extension.ml",
    "chars": 52,
    "preview": "\nlet _ = [%js.of: int]\nlet _ = [%js.of: int -> int]\n"
  },
  {
    "path": "ppx-test/first_class_modules.mli",
    "chars": 1933,
    "preview": "module[@js.scope \"console\"] Console: sig\n  val log: (module[@js] Ojs.T with type t = 'a) -> 'a -> unit [@@js.global \"log"
  },
  {
    "path": "ppx-test/issues.ml",
    "chars": 1843,
    "preview": "module Issue116 = [%js: type t]\nmodule Issue117 = [%js:\n  module T: sig\n    val log: 'a -> unit [@@js.global]\n    val lo"
  },
  {
    "path": "ppx-test/issues_mli.mli",
    "chars": 94,
    "preview": "module Issue144: sig\n  type t\n  val f: t -> (args:int -> int [@js.dummy]) [@@js.call \"f\"]\nend\n"
  },
  {
    "path": "ppx-test/modules.mli",
    "chars": 283,
    "preview": "module Event: sig\n  type t = private Ojs.t\n  val t_to_js: t -> Ojs.t\n  val t_of_js: Ojs.t -> t\nend\n\nmodule Foo: sig\n  mo"
  },
  {
    "path": "ppx-test/ppx/dune",
    "chars": 68,
    "preview": "(executable\n (name main)\n (libraries ppxlib gen_js_api_ppx_driver))\n"
  },
  {
    "path": "ppx-test/ppx/main.ml",
    "chars": 102,
    "preview": "\n(* To run as a standalone binary, run the registered drivers *)\nlet () = Ppxlib.Driver.standalone ()\n"
  },
  {
    "path": "ppx-test/recursive_modules.mli",
    "chars": 506,
    "preview": "module [@js.scope \"Foo\"] rec Foo : sig\n  type t = private Ojs.t\n  val t_of_js: Ojs.t -> t\n  val t_to_js: t -> Ojs.t\n  va"
  },
  {
    "path": "ppx-test/scoped.mli",
    "chars": 897,
    "preview": "(* The gen_js_api is released under the terms of an MIT-like license.     *)\n(* See the attached LICENSE file.          "
  },
  {
    "path": "ppx-test/types.ml",
    "chars": 5166,
    "preview": "\ntype 'a of_js = Ojs.t -> 'a\ntype 'a to_js = 'a -> Ojs.t\n\n(** JS-able types *)\n\nlet _ : string of_js = [%js.to: string]\n"
  },
  {
    "path": "ppx-test/union_and_enum.mli",
    "chars": 4808,
    "preview": "type enum_int =\n  | Enum_int_0 [@js 0]\n  | Enum_int_1 [@js 1]\n  | Enum_int_other of int [@js.default]\n  [@@js.enum]\n\ntyp"
  }
]

About this extraction

This page contains the full source code of the LexiFi/gen_js_api GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 114 files (352.5 KB), approximately 108.8k tokens, and a symbol index with 6 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!