Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
[![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes)
[![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes)
[![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes)
[![LiveCodes: languages](https://img.shields.io/badge/languages-123-blue)](https://livecodes.io/docs/languages/)
[![LiveCodes: languages](https://img.shields.io/badge/languages-124-blue)](https://livecodes.io/docs/languages/)
[![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/)
[![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt)
[![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt)
Expand Down
93 changes: 93 additions & 0 deletions docs/docs/languages/ocaml-js.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# OCaml (JS)

[OCaml](https://ocaml.org/) is an industrial-strength programming language supporting functional, imperative and object-oriented styles.

LiveCodes runs the OCaml compiler itself, built with [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml), so compilation happens in the browser and nothing is sent to a server. The compiler emits a JavaScript program, which the result page then runs.

:::info Note

LiveCodes also has an `ocaml` language, which runs the [ReScript](https://rescript-lang.org/) compiler. It is deprecated in favour of this one. Read documentation [here](./ocaml.mdx).

:::

## Demo

import LiveCodes from '../../src/components/LiveCodes.tsx';

export const params = {
'ocaml-js': 'let () =\n print_endline "Hello, World!"\n',
console: 'full',
};

<LiveCodes params={params}></LiveCodes>

## Usage

LiveCodes runs OCaml in the browser, including the standard library.

Because the compiled program *is* JavaScript by the time it runs, it can interact with the page. JavaScript interoperability and DOM access come from [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml)'s `Js` and `Dom_html` with `open Js_of_ocaml` (see the [example below](#example-usage)).

## Modules and Libraries

The standard library is always available. Beyond it, these are linked on demand — the archive is fetched the first time a program names one of its modules, so a program that uses none of them downloads none of them.

- **js_of_ocaml** — `Js`, `Dom_html`, and the rest of the browser APIs
- **Str**, **Unix**, **Graphics** — from the OCaml distribution
- **Lwt**, **js_of_ocaml-lwt** — promises and concurrency
- **Re** — regular expressions
- **jsonm**, **xmlm**, **uutf** — JSON, XML and Unicode text
- **fmt**, **logs** — formatting and logging
- **base64** — base64 encoding
- **Zarith** — `Z` and `Q`, arbitrary-precision integers and rationals

Everything here runs in the browser, so a library has to be pure OCaml, or have a JavaScript replacement for its C stubs — Zarith's are provided by `zarith_stubs_js`. Anything needing real threads, processes or a filesystem will not work, whatever is linked.

This is the set built with the compiler. Other opam packages are not available.

## Language Info

### Name

`ocaml-js`

### Extensions

`js.ocaml`, `js.ml`

### Editor

`script`

## Compiler

The OCaml compiler — the same `compiler-libs` frontend that compiles ordinary OCaml — compiled to JavaScript with [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml). It is published as [@live-codes/ocaml](https://www.npmjs.com/package/@live-codes/ocaml).

### Version

`@live-codes/ocaml`: v0.2.0

## Code Formatting

Not supported.

## Limitations

There is no ppx support, since a ppx would have to run at compile time and compilation happens at run time here. So `##`, `##.` and `[%js]` are not available; use `Js.Unsafe` and the rest of the bindings instead.

## Example Usage

This example counts button clicks in the DOM, using `Dom_html`:

<LiveCodes template="ocaml-js" height="80vh"></LiveCodes>

## Starter Template

https://livecodes.io/?template=ocaml-js

## Links

- [OCaml website](https://ocaml.org/)
- [OCaml documentation](https://ocaml.org/docs/)
- [@live-codes/ocaml on npm](https://www.npmjs.com/package/@live-codes/ocaml)
- [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml)
- [OCaml with the ReScript compiler](./ocaml.mdx) in LiveCodes
12 changes: 12 additions & 0 deletions docs/docs/languages/ocaml.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

LiveCodes compiles OCaml code to JavaScript using the [ReScript compiler](https://rescript-lang.org/). OCaml in LiveCodes supports JSX via a ReasonReact-compatible syntax.

:::info Deprecation Note

This language is deprecated in favour of [OCaml (JS)](./ocaml-js.mdx).

To continue using this language use the language name `rescript-ocaml`.

:::

## Usage

### Demo
Expand Down Expand Up @@ -66,6 +74,10 @@ OCaml React does not support React 19. Use an import map (in [custom settings](.

`ocaml`

### Aliases

`rescript-ocaml`

### Extensions

`.ml`, `.mli`
Expand Down
1 change: 1 addition & 0 deletions docs/src/components/LanguageSliders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export default function Sliders() {
{ name: 'elm', title: 'Elm' },
{ name: 'rescript', title: 'ReScript' },
{ name: 'reason', title: 'Reason' },
{ name: 'ocaml-js', title: 'OCaml (JS)' },
{ name: 'ocaml', title: 'OCaml' },
{ name: 'nim', title: 'Nim' },
{ name: 'nim-wasm', title: 'Nim (Wasm)' },
Expand Down
1 change: 1 addition & 0 deletions docs/src/components/TemplateList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const templates = [
{ name: 'rescript', title: 'ReScript Starter', thumbnail: 'rescript.png' },
{ name: 'reason', title: 'Reason Starter', thumbnail: 'reason.svg' },
{ name: 'ocaml', title: 'Ocaml Starter', thumbnail: 'ocaml.svg' },
{ name: 'ocaml-js', title: 'OCaml (JS) Starter', thumbnail: 'ocaml.svg' },
{ name: 'nim', title: 'Nim Starter', thumbnail: 'nim.svg' },
{ name: 'nim-wasm', title: 'Nim (Wasm) Starter', thumbnail: 'nim.svg' },
{ name: 'janet-wasm', title: 'Janet (Wasm) Starter', thumbnail: 'janet.png' },
Expand Down
24 changes: 24 additions & 0 deletions e2e/specs/compilers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,30 @@ export class App {
};`);
});

test('OCaml (JS)', async ({ page, getTestUrl }) => {
await page.goto(getTestUrl());

const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);

await app.click(':nth-match([title="Change Language"], 3)');
await (await app.$('[data-lang="ocaml-js"]'))?.click();
await waitForEditorFocus(app);
await page.keyboard.insertText(
[
'let () =',
' let squares = List.init 5 (fun i -> i * i) in',
' Printf.printf "sum=%d\\n" (List.fold_left (+) 0 squares)',
].join('\n'),
);

await waitForResultUpdate();
const resultText = await getResult().innerHTML('body > script');

// The real OCaml compiler, compiled to JavaScript, emitted a bundle the page runs.
expect(resultText).toContain('// Generated by js_of_ocaml');
expect(resultText).toContain('sum=');
});

test('LiveScript', async ({ page, getTestUrl, editor }) => {
test.skip(editor === 'codejar', 'please fix');

Expand Down
1 change: 1 addition & 0 deletions functions/vendors/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const starterTemplates = {
"rescript": "ReScript Starter",
"reason": "Reason Starter",
"ocaml": "Ocaml Starter",
"ocaml-js": "OCaml (JS) Starter",
"nim": "Nim Starter",
"nim-wasm": "Nim (Wasm) Starter",
"crystal-wasm": "Crystal Starter",
Expand Down
1 change: 1 addition & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ const esmBuild = () =>
'languages/postgresql/lang-postgresql-compiler-esm.ts',
'languages/duckdb/lang-duckdb-compiler-esm.ts',
'languages/r/lang-r-script-esm.ts',
'languages/ocaml-js/lang-ocaml-js-compiler-esm.ts',
'languages/rescript/lang-rescript-compiler-esm.ts',
'i18n/i18n.ts',
]
Expand Down
1 change: 1 addition & 0 deletions server/php/inc/starter-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"rescript": "ReScript Starter",
"reason": "Reason Starter",
"ocaml": "Ocaml Starter",
"ocaml-js": "OCaml (JS) Starter",
"nim": "Nim Starter",
"nim-wasm": "Nim (Wasm) Starter",
"crystal-wasm": "Crystal Starter",
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/UI/command-menu-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ export const getCommandMenuActions = ({
'rescript',
'reason',
'ocaml',
'ocaml-js',
'nim',
'nim-wasm',
'janet-wasm',
Expand Down
Loading
Loading