Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] 1.0.0 patches #97

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,25 @@ jobs:
with:
python-version: 3.x
- run: python3 -m pip install -r ./pip-requirements.txt
- uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: 4.14.x
dune-cache: false # can cause trouble when generating melange docs in step below: https://github.com/ocaml/dune/issues/7720
- name: Install all deps
run: make install
- name: Generate melange docs in ml syntax
run: opam reinstall -y melange --with-doc
- name: Copy melange docs in ml syntax
run: cp -r _opam/.opam-switch/build/melange.dev/_build/default/_doc/_html docs/api/ml
- name: Generate melange docs in re syntax
run: ODOC_SYNTAX="re" opam reinstall -y melange --with-doc
- name: Copy melange docs in re syntax
run: cp -r _opam/.opam-switch/build/melange.dev/_build/default/_doc/_html docs/api/re
# We don't want to run it for now (until v2 is published)
# - name: Run canonical script
# run: opam exec -- dune exec add_canonical docs/api
- name: Build playground
run: make build-playground
- name: Configure Git user
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
Expand Down
21 changes: 19 additions & 2 deletions .github/workflows/publish-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,27 @@ jobs:
with:
python-version: 3.x
- run: python3 -m pip install -r ./pip-requirements.txt
- uses: ocaml/setup-ocaml@v2
with:
ocaml-compiler: 4.14.x
dune-cache: false # can cause trouble when generating melange docs in step below: https://github.com/ocaml/dune/issues/7720
- name: Install all deps
run: make install
- name: Generate melange docs in ml syntax
run: opam reinstall -y melange --with-doc
- name: Copy melange docs in ml syntax
run: cp -r _opam/.opam-switch/build/melange.dev/_build/default/_doc/_html docs/api/ml
- name: Generate melange docs in re syntax
run: ODOC_SYNTAX="re" opam reinstall -y melange --with-doc
- name: Copy melange docs in re syntax
run: cp -r _opam/.opam-switch/build/melange.dev/_build/default/_doc/_html docs/api/re
- name: Run canonical script
run: opam exec -- dune exec add_canonical docs/api
- name: Build playground
run: make build-playground
- name: Configure Git user
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
- run: git fetch origin gh-pages --depth=1
- run: mike deploy ${{ github.ref_name }}
- run: mike set-default --push ${{ github.ref_name }}
- run: mike deploy --push ${{ github.ref_name }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ _build
_opam
.vscode
.DS_Store

docs/playground
docs/api/ml
docs/api/re
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,15 @@ format: ## Format the codebase with ocamlformat
.PHONY: format-check
format-check: ## Checks if format is correct
$(DUNE) build @fmt

.PHONY: build-playground
build-playground: install ## Builds the playground
$(DUNE) build @playground-assets
cd playground && yarn && yarn build

.PHONY: move-v1.0.0-tag
move-v1.0.0-tag: ## Moves the v1.0.0 tag to the latest commit, to be called from branch 1.0.0-patches
git push origin :refs/tags/v1.0.0
git tag -fa v1.0.0
git push origin --tags

16 changes: 11 additions & 5 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

Melange exposes three libraries:

- A standard library, which mostly replicates that of OCaml for compatibility;
see the docs: the [`Stdlib`](todo-fix-me.md) library
- Bindings to several browser and Node JavaScript APIs in the [`Js`
library](todo-fix-me.md).
- Data structures and collection types in the [`Belt` library](todo-fix-me.md)
- A standard library, which mostly replicates that of OCaml for compatibility:
the <a class="text-ocaml" href="../api/ml/melange/Stdlib"><code>Stdlib</code>
library</a><a class="text-reasonml"
href="../api/re/melange/Stdlib"><code>Stdlib</code> library</a>
- Bindings to several browser and Node JavaScript APIs in the <a
class="text-ocaml" href="../api/ml/melange/Js"><code>Js</code> library</a><a
class="text-reasonml" href="../api/re/melange/Js"><code>Js</code> library</a>
- Data structures and collection types in the <a class="text-ocaml"
href="../api/ml/melange/Belt"><code>Belt</code> library</a><a
class="text-reasonml" href="../api/re/melange/Belt"><code>Belt</code>
library</a>

Using one or the other will depend on your application requirements, how much
integration you need with existing JavaScript libraries, or other specific
Expand Down
File renamed without changes.
135 changes: 91 additions & 44 deletions docs/communicate-with-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,11 @@ class="text-reasonml">\-\></code>.
As its name suggests, the pipe first operator is better suited for functions
where the data is passed as the first argument.

The functions in the [`Belt` library](todo-fix-me.md) included with Melange have
been designed with the data-first convention in mind, so they work best with the
pipe first operator.
The functions in the <a class="text-ocaml"
href="../api/ml/melange/Belt"><code>Belt</code> library</a><a
class="text-reasonml" href="../api/re/melange/Belt"><code>Belt</code>
library</a> included with Melange have been designed with the data-first
convention in mind, so they work best with the pipe first operator.

For example, we can rewrite the example above using `Belt.List.map` and the pipe
first operator:
Expand Down Expand Up @@ -461,8 +463,8 @@ This is how each Melange type is converted into JavaScript values:
| array | array |
| tuple `(3, 4)` | array `[3, 4]` |
| bool | boolean |
| [Js.Nullable.t](todo-fix-me.md) | `null` / `undefined` |
| [Js.Re.t](todo-fix-me.md) | [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) |
| <a class="text-ocaml" href="../api/ml/melange/Js/#module-Nullable">Js.Nullable.t</a><a class="text-reasonml" href="../api/re/melange/Js/#module-Nullable">Js.Nullable.t</a> | `null` / `undefined` |
| <a class="text-ocaml" href="../api/ml/melange/Js/#module-Re">Js.Re.t</a><a class="text-reasonml" href="../api/re/melange/Js/#module-Re">Js.Re.t</a> | [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) |
| Option.t `None` | `undefined` |
| Option.t <code class="text-ocaml">Some( Some .. Some (None))</code><code class="text-reasonml">Some(Some( .. Some(None)))</code> | internal representation |
| <p>foo</p> | `2` |
Expand Down Expand Up @@ -577,9 +579,14 @@ You can surround the interpolation variable in parentheses too: `{j|你
好,$(world)|j}`.

To work with strings, the Melange standard library provides some utilities in
the [`Stdlib.String` module](todo-fix-me.md). The bindings to the native
JavaScript functions to work with strings are in the [`Js.String`
module](todo-fix-me.md).
the <a class="text-ocaml"
href="../api/ml/melange/Stdlib/String"><code>Stdlib.String</code> module</a><a
class="text-reasonml"
href="../api/re/melange/Stdlib/String"><code>Stdlib.String</code> module</a>.
The bindings to the native JavaScript functions to work with strings are in the
<a class="text-ocaml" href="../api/ml/melange/Js/#module-String"><code>Js.String</code>
module</a><a class="text-reasonml"
href="../api/re/melange/Js/#module-String"><code>Js.String</code> module</a>.

#### Floating-point numbers

Expand All @@ -589,9 +596,14 @@ with a 53-bit mantissa and exponents from -1022 to 1023. This happens to be the
same encoding as [JavaScript
numbers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding),
so values of these types can be used transparently between Melange code and
JavaScript code. The Melange standard library provides a [`Stdlib.Float`
module](todo-fix-me.md). The bindings to the JavaScript APIs that manipulate
float values can be found in the [`Js.Float`](todo-fix-me.md) module.
JavaScript code. The Melange standard library provides a <a class="text-ocaml"
href="../api/ml/melange/Stdlib/Float"><code>Stdlib.Float</code> module</a><a
class="text-reasonml"
href="../api/re/melange/Stdlib/Float"><code>Stdlib.Float</code> module</a>. The
bindings to the JavaScript APIs that manipulate float values can be found in the
<a class="text-ocaml" href="../api/ml/melange/Js/#module-Float"><code>Js.Float</code>
module</a><a class="text-reasonml"
href="../api/re/melange/Js/#module-Float"><code>Js.Float</code> module</a>.

#### Integers

Expand All @@ -607,9 +619,14 @@ allowing for a larger range of representable integers in JavaScript compared to
Melange. When dealing with large numbers, it is advisable to use floats instead.
For instance, floats are used in bindings like `Js.Date`.

The Melange standard library provides a [`Stdlib.Int` module](todo-fix-me.md).
The bindings to work with JavaScript integers are in the
[`Js.Int`](todo-fix-me.md) module.
The Melange standard library provides a <a class="text-ocaml"
href="../api/ml/melange/Stdlib/Int"><code>Stdlib.Int</code> module</a><a
class="text-reasonml"
href="../api/re/melange/Stdlib/Int"><code>Stdlib.Int</code> module</a>. The
bindings to work with JavaScript integers are in the <a class="text-ocaml"
href="../api/ml/melange/Js/#module-Int"><code>Js.Int</code> module</a><a
class="text-reasonml" href="../api/re/melange/Js/#module-Int"><code>Js.Int</code>
module</a>.

#### Arrays

Expand All @@ -618,11 +635,16 @@ arrays, all the values in a Melange array need to have the same type.

Another difference is that OCaml arrays are fixed-sized, but on Melange side
this constraint is relaxed. You can change an array’s length using functions
like `Js.Array.push`, available in the bindings to the JavaScript APIs in
[`Js.Array`](todo-fix-me.md).
like `Js.Array.push`, available in the bindings to the JavaScript APIs in the <a
class="text-ocaml" href="../api/ml/melange/Js/#module-Array"><code>Js.Array</code>
module</a><a class="text-reasonml"
href="../api/re/melange/Js/#module-Array"><code>Js.Array</code> module</a>.

Melange standard library also has a module to work with arrays, available in
`Stdlib.Array`(todo-fix-me.md) module.
Melange standard library also has a module to work with arrays, available in the
<a class="text-ocaml"
href="../api/ml/melange/Stdlib/Array"><code>Stdlib.Array</code> module</a><a
class="text-reasonml"
href="../api/re/melange/Stdlib/Array"><code>Stdlib.Array</code> module</a>.

#### Tuples

Expand Down Expand Up @@ -684,9 +706,11 @@ Will compile to:
var r = /b/g;
```

A regular expression like the above is of type `Js.Re.t`. The
[`Js.Re`](todo-fix-me.md) module provides the bindings to the JavaScript
functions that operate over regular expressions.
A regular expression like the above is of type `Js.Re.t`. The <a
class="text-ocaml" href="../api/ml/melange/Js/#module-Re"><code>Js.Re</code>
module</a><a class="text-reasonml"
href="../api/re/melange/Js/#module-Re"><code>Js.Re</code> module</a> provides the
bindings to the JavaScript functions that operate over regular expressions.

## Non-shared data types

Expand All @@ -699,10 +723,16 @@ them before doing so.
[some helpers](#generate-getters-setters-and-constructors) to do so.
- Exceptions
- Option (a variant type): Better use the `Js.Nullable.fromOption` and
`Js.Nullable.toOption` functions in the [`Js.Nullable` module](todo-fix-me.md)
to transform them into either `null` or `undefined` values.
- List (also a variant type): use `Array.of_list` and `Array.to_list` in the
[`Array` module](todo-fix-me.md).
`Js.Nullable.toOption` functions in the <a class="text-ocaml"
href="../api/ml/melange/Js/#module-Nullable"><code>Js.Nullable</code> module</a><a
class="text-reasonml"
href="../api/re/melange/Js/#module-Nullable"><code>Js.Nullable</code> module</a> to
transform them into either `null` or `undefined` values.
- List (also a variant type): use `Array.of_list` and `Array.to_list` in the <a
class="text-ocaml"
href="../api/ml/melange/Stdlib/Array"><code>Stdlib.Array</code> module</a><a
class="text-reasonml"
href="../api/re/melange/Stdlib/Array"><code>Stdlib.Array</code> module</a>.
- Character
- Int64
- Lazy values
Expand All @@ -727,9 +757,9 @@ These attributes are used to annotate `external` definitions:
- [`bs.return`](#wrapping-returned-nullable-values): automate conversion from
nullable values to `Option.t` values
- [`bs.send`](#calling-an-object-method): call a JavaScript object method using
[pipe first](todo-fix-me.md) convention
[pipe first](#pipe-first) convention
- [`bs.send.pipe`](#calling-an-object-method): call a JavaScript object method
using [pipe last](todo-fix-me.md) convention
using [pipe last](#pipe-last) convention
- [`bs.set`](#bind-to-object-properties): set JavaScript object properties
statically by name, using the dot notation `.`
- [`bs.set_index`](#bind-to-object-properties): set JavaScript object properties
Expand Down Expand Up @@ -1356,8 +1386,10 @@ Sometimes JavaScript objects are used as dictionaries. In these cases:

For this particular use case of JavaScript objects, Melange exposes a specific
type `Js.Dict.t`. The values and functions to work with values of this type are
defined in the [`Js.Dict`](todo-fix-me.md) module, with operations like `get`,
`set`, etc.
defined in the <a class="text-ocaml"
href="../api/ml/melange/Js/#module-Dict"><code>Js.Dict</code> module</a><a
class="text-reasonml" href="../api/re/melange/Js/#module-Dict"><code>Js.Dict</code>
module</a>, with operations like `get`, `set`, etc.

Values of the type `Js.Dict.t` compile to JavaScript objects.

Expand Down Expand Up @@ -1431,8 +1463,10 @@ let () = clearTimeout(id);
```

> **_NOTE:_** The bindings to `setTimeout` and `clearTimeout` are shown here for
> learning purposes, but they are already available in the
> [`Js.Global`](todo-fix-me.md) module.
> learning purposes, but they are already available in the <a class="text-ocaml"
> href="../api/ml/melange/Js/#module-Global"><code>Js.Global</code> module</a><a
> class="text-reasonml"
> href="../api/re/melange/Js/#module-Global"><code>Js.Global</code> module</a>.

Generates:

Expand Down Expand Up @@ -2292,10 +2326,14 @@ discarded. The value returned from the operation would not be the addition of
the two numbers, but rather the inner anonymous callback.

To solve this mismatch between OCaml and JavaScript functions and their
application, Melange provides a special attribute `@bs` that can be used to annotate
external functions that need to be "uncurried".
application, Melange provides a special attribute `@bs` that can be used to
annotate external functions that need to be "uncurried".

<span class="text-reasonml">In Reason syntax, this attribute does not need to be written explicitly, as it is deeply integrated with the Reason parser. To specify some function type as "uncurried", one just needs to add the dot character `.` to the function type. For example, `(. 'a, 'b) => 'c` instead of `('a, 'b) => 'c`.</span>
<span class="text-reasonml">In Reason syntax, this attribute does not need to be
written explicitly, as it is deeply integrated with the Reason parser. To
specify some function type as "uncurried", one just needs to add the dot
character `.` to the function type. For example, `(. 'a, 'b) => 'c` instead of
`('a, 'b) => 'c`.</span>

In the example above:

Expand All @@ -2309,7 +2347,12 @@ external map : 'a array -> 'b array -> (('a -> 'b -> 'c)[@bs]) -> 'c array
external map: (array('a), array('b), (. 'a, 'b) => 'c) => array('c) = "map";
```

Here <span class="text-ocaml">`('a -> 'b -> 'c [@bs])`</span><span class="text-reasonml">`(. 'a, 'b) => 'c`</span>will be interpreted as having arity 2. In general, <span class="text-ocaml">`'a0 -> 'a1 ...​ 'aN -> 'b0 [@bs]` is the same as `'a0 -> 'a1 ...​ 'aN -> 'b0`</span><span class="text-reasonml">`. 'a0, 'a1, ...​ 'aN => 'b0` is the same as `'a0, 'a1, ...​ 'aN => 'b0`</span> except the former’s arity is guaranteed to be N while the latter is unknown.
Here <span class="text-ocaml">`('a -> 'b -> 'c [@bs])`</span><span
class="text-reasonml">`(. 'a, 'b) => 'c`</span>will be interpreted as having
arity 2. In general, <span class="text-ocaml">`'a0 -> 'a1 ...​ 'aN -> 'b0 [@bs]`
is the same as `'a0 -> 'a1 ...​ 'aN -> 'b0`</span><span class="text-reasonml">`.
'a0, 'a1, ...​ 'aN => 'b0` is the same as `'a0, 'a1, ...​ 'aN => 'b0`</span>
except the former’s arity is guaranteed to be N while the latter is unknown.

If we try now to call `map` using `add`:

Expand All @@ -2330,7 +2373,8 @@ This expression has type int -> int -> int
but an expression was expected of type ('a -> 'b -> 'c) Js.Fn.arity2
```

To solve this, we add <span class="text-ocaml">`@bs`</span><span class="text-reasonml">`.`</span> in the function definition as well:
To solve this, we add <span class="text-ocaml">`@bs`</span><span
class="text-reasonml">`.`</span> in the function definition as well:

```ocaml
let add = fun [@bs] x y -> x + y
Expand Down Expand Up @@ -2430,12 +2474,13 @@ Note that the first argument will be reserved for `this`.
### Wrapping returned nullable values

JavaScript models `null` and `undefined` differently, whereas it can be useful
to treat both as `'a option` in OCaml.
to treat both as <span class="text-ocaml">`'a option`</span><span
class="text-reasonml">`option('a)`</span> in Melange.

Melange understands the `bs.return` attribute in externals to model how
nullable return types should be wrapped at the OCaml <-> JavaScript boundary.
An `external` value with `bs.return` converts the return value to an `option`
type, avoiding the need for extra wrapping / unwrapping with functions such as
Melange understands the `bs.return` attribute in externals to model how nullable
return types should be wrapped at the bindings boundary. An `external` value
with `bs.return` converts the return value to an `option` type, avoiding the
need for extra wrapping / unwrapping with functions such as
`Js.Nullable.toOption`.

```ocaml
Expand Down Expand Up @@ -2478,9 +2523,11 @@ function test($$document) {
}
```

The `bs.return` attribute takes an attribute payload, as seen with `[@@bs.return
nullable]` above. Currently 4 directives are supported: `null_to_opt`,
`undefined_to_opt`, `nullable` and `identity`.
The `bs.return` attribute takes an attribute payload, as seen with <span
class="text-ocaml">`[@@bs.return nullable]`</span><span
class="text-reasonml">`[@bs.return nullable]`</span> above. Currently 4
directives are supported: `null_to_opt`, `undefined_to_opt`, `nullable` and
`identity`.

`nullable` is encouraged, as it will convert from `null` and `undefined` to
`option` type.
Expand Down
Loading