Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
46e6fcd
Rewrite rewatch in OCaml
cknitt Sep 22, 2026
d25e750
Use the parent workspace's settings for OCaml rewatch member builds
cknitt Oct 10, 2026
06e8aa3
Name OCaml rewatch namespaces with an entry like Rust rewatch
cknitt Oct 10, 2026
d8730e4
Handle SIGHUP and SIGQUIT in OCaml rewatch
cknitt Oct 10, 2026
4640c05
Print plain OCaml rewatch usage errors when stderr is not a terminal
cknitt Oct 10, 2026
9b0e2b3
Support OCaml rewatch locks on filesystems without hard links
cknitt Oct 10, 2026
b01ed1f
Add OCaml rewatch changelog fragments and remove its task brief
cknitt Oct 12, 2026
ffd3dfb
Test OCaml rewatch signal handling during a js-post-build hook
cknitt Oct 10, 2026
b25d74f
Accept only build-system executables as rewatch lock owners
cknitt Oct 10, 2026
c6d750b
Separate OCaml rewatch config diagnostics from warnings like Rust
cknitt Oct 10, 2026
da81813
Compare the OCaml rewatch CLI help exactly in cli_help
cknitt Oct 10, 2026
2dc0a6b
Remove the Rust unit-test mapping check from OCaml rewatch CI
cknitt Oct 10, 2026
ee7e91f
Add libuv's externally maintained parts to the rewatch notices
cknitt Oct 10, 2026
32dcf7f
Copy the Cargo-built rewatch to rescript-rust.exe again
cknitt Oct 10, 2026
7372127
Clean up small OCaml rewatch review findings
cknitt Oct 10, 2026
77b5724
Rewrite the OCaml rewatch docs for maintainers
cknitt Oct 10, 2026
18fde45
Reject non-standard JSON in rescript.json in OCaml rewatch
cknitt Oct 10, 2026
86bb43c
Name fields and accepted values in OCaml rewatch config errors
cknitt Oct 10, 2026
e70977d
Honor -v for OCaml rewatch format and compiler-args
cknitt Oct 10, 2026
f7bed45
Restore Rust rewatch's project-context debug wording in OCaml rewatch
cknitt Oct 10, 2026
5e5902c
Describe created project contexts in plain words in both rewatches
cknitt Oct 10, 2026
d8df3f4
Tighten OCaml rewatch process lookups on Windows
cknitt Oct 10, 2026
ccc8c0c
Harden the OCaml rewatch Windows process launcher
cknitt Oct 10, 2026
6cf153f
Clean up stale artifacts once for cleaned packages
cknitt Oct 10, 2026
1d0be16
Track removed modules once per attempt
cknitt Oct 10, 2026
da3b7ba
Compare graph nodes when carrying dirtiness forward
cknitt Oct 10, 2026
b3b1080
Simplify incremental preparation
cknitt Oct 10, 2026
b799c5a
Move the build kind into Build_report
cknitt Oct 10, 2026
cbd65a2
Define build step labels once in Build_report
cknitt Oct 10, 2026
62ebf6a
Remove unreachable build failure handling
cknitt Oct 10, 2026
7b9b7b8
Drop redundant once-guards in Build_attempt
cknitt Oct 10, 2026
2e48bce
Simplify package plans and preparation
cknitt Oct 10, 2026
447b545
Require cleanup inventories in Build_artifacts.cleanup_stale
cknitt Oct 10, 2026
7e220c1
Split parser and compiler flags
cknitt Oct 10, 2026
977f4ec
Reuse Compiler_info.clean_package in clean
cknitt Oct 10, 2026
de86da6
Reword session comments in build.ml
cknitt Oct 10, 2026
ae9484e
Report format's package name mismatch once
cknitt Oct 10, 2026
2d29203
Simplify watch snapshot comparison and walk
cknitt Oct 10, 2026
3b10a05
Share watcher rebuild and reconciliation steps
cknitt Oct 10, 2026
f7dc1de
Simplify CLI argument predicates and evaluation
cknitt Oct 10, 2026
112b8e6
Reuse workspace_config_for in format's scope check
cknitt Oct 10, 2026
d306858
Remove config_types.mli, which duplicated config_types.ml
cknitt Oct 10, 2026
e264334
Split Config.load into named decoders
cknitt Oct 10, 2026
a853f89
Simplify source discovery options
cknitt Oct 10, 2026
77099e6
Share watch scope's source directory check
cknitt Oct 10, 2026
81c6c32
Remove small duplications in config, watch and traversal code
cknitt Oct 10, 2026
28f0808
Create native watchers by refreshing an empty watcher
cknitt Oct 10, 2026
58819c5
Remove termination-signal deferral from rewatch-ocaml
cknitt Oct 10, 2026
86abce5
Drop the unused root_reaped parameter of signal_process_tree
cknitt Oct 10, 2026
913ba2f
Simplify fail_launch in process_child
cknitt Oct 10, 2026
e82c124
Remove parameters that never vary in rewatch-ocaml
cknitt Oct 10, 2026
b14694a
Remove unused exports and trivial wrappers in rewatch-ocaml
cknitt Oct 10, 2026
d125c42
Remove unreachable defensive errors in rewatch-ocaml
cknitt Oct 10, 2026
55e693d
Share the lock acquisition loop of with_build and with_watch
cknitt Oct 10, 2026
0db1b11
Reject cyclic graphs in run_dependency_graph
cknitt Oct 10, 2026
d72be72
Remove diagnostic bench scripts
cknitt Oct 10, 2026
a367fc1
Remove orphaned Windows job stub check
cknitt Oct 10, 2026
6a0a690
Simplify run.sh setup and teardown
cknitt Oct 10, 2026
81727a0
Drop Package_traversal.For_test
cknitt Oct 10, 2026
66429a4
Factor repeated runs out of check_command_validation.sh
cknitt Oct 10, 2026
cffd001
Consolidate configuration unit tests
cknitt Oct 10, 2026
e94c02c
Drop run.sh cases duplicated by the shared suite
cknitt Oct 10, 2026
451c4b4
Drop output tests that restate message formats
cknitt Oct 10, 2026
cca3c49
Drop CLI precedence tests duplicated by command validation
cknitt Oct 10, 2026
fc9c4a3
Drop self-checks from check_verbose_output.sh
cknitt Oct 10, 2026
2ee6d54
Skip rewatch parity steps on the oldest-OCaml CI job
cknitt Oct 10, 2026
3579650
Run the Rust rewatch shared suite on linux-arm64 only
cknitt Oct 10, 2026
52bcf1b
Ignore obsolete jsx.mode and jsx.v3-dependencies in OCaml rewatch
cknitt Oct 10, 2026
a9282c4
Explain the process group escalation's PID reuse window
cknitt Oct 10, 2026
b9431b3
Don't let OCaml rewatch watch exit wait for another build's lock
cknitt Oct 10, 2026
b03f623
Port Rust rewatch's option descriptions to the OCaml CLI help
cknitt Oct 10, 2026
82ac1a2
Poll for watch handles instead of sleeping in OCaml rewatch tests
cknitt Oct 10, 2026
97cc8f7
Don't republish the .cmi after an implementation with an interface
cknitt Oct 10, 2026
9c78b54
Restore with_lock in OCaml rewatch for OCaml 5.0
cknitt Oct 10, 2026
171e9f2
Clear a killed watcher's build lock in the Windows command checks
cknitt Oct 10, 2026
b0e51da
Name the failing command in OCaml rewatch's focused tests under bash
cknitt Oct 10, 2026
f6b3728
Show the bytes behind Windows output mismatches in OCaml rewatch tests
cknitt Oct 10, 2026
127757b
Don't format-check an LF fixture in OCaml rewatch's focused tests
cknitt Oct 10, 2026
5c4c416
Report why OCaml rewatch's watcher exits, as Rust does
cknitt Oct 11, 2026
7c14738
Lock the test proxy's call log so Windows appends don't collide
cknitt Oct 11, 2026
143914a
Lock a separate file for the test proxy's call log
cknitt Oct 11, 2026
b20240d
Only warn when Rust's inverted watch filter doesn't reproduce
cknitt Oct 11, 2026
1ba1430
Use the same, longer waits on every platform in rewatch tests
cknitt Oct 12, 2026
34ca1bc
Test OCaml rewatch's module names against Rust's new cases
cknitt Oct 12, 2026
2cacfd7
Remove a partial destination when an OCaml rewatch copy fails
cknitt Oct 12, 2026
5d1b4ec
Print watcher output when the dependency-fallback test times out
cknitt Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
19 changes: 17 additions & 2 deletions .github/actions/setup-ocaml/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ runs:
run: |
dependency_flags_key="${DEPENDENCY_FLAGS//--/}"
dependency_flags_key="${dependency_flags_key// /_}"
key="$CACHE_PREFIX-$OS-3.9.0-$COMPILER-$dependency_flags_key-${{ hashFiles('*.opam') }}"
dependency_hash="${{ hashFiles('*.opam', '.github/opam-repository/repo', '.github/opam-repository/packages/**') }}"
key="$CACHE_PREFIX-$OS-3.9.0-$COMPILER-$dependency_flags_key-$dependency_hash"
echo "value=${key//,/-}" >> "$GITHUB_OUTPUT"
echo "setup-version=3.9.0" >> "$GITHUB_OUTPUT"

Expand All @@ -104,6 +105,11 @@ runs:
uses: ocaml/setup-ocaml@v3.9.0
with:
ocaml-compiler: ${{ inputs.compiler }}
# Use the HTTP repository to prevent intermittent CI setup failures:
# the Git-backed default can race with detached Git maintenance while
# OPAM scans it (https://github.com/ocaml/opam/issues/7031).
opam-repositories: |
default: https://opam.ocaml.org
opam-pin: false
cache: false

Expand All @@ -125,12 +131,21 @@ runs:
env:
DEPENDENCY_FLAGS: ${{ inputs.dependency-flags }}
run: |
opam repository add rescript-overrides "$GITHUB_WORKSPACE/.github/opam-repository"
read -ra dependency_flags <<< "$DEPENDENCY_FLAGS"
if [[ "$RUNNER_OS" == "Windows" ]]; then
export AR=x86_64-w64-mingw32-ar
export RANLIB=x86_64-w64-mingw32-ranlib
export STRIP=x86_64-w64-mingw32-strip
export NM=x86_64-w64-mingw32-nm
export DLLTOOL=x86_64-w64-mingw32-dlltool
export OBJDUMP=x86_64-w64-mingw32-objdump
fi
opam install . "${dependency_flags[@]}"

- name: Cache OPAM environment
# Caches created by pull_request runs are scoped to that PR's merge ref
# and cannot seed other PRs or branches. Only pushes create shared caches.
# and cannot seed other PRs or branches, so only push runs save them.
if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'push'
uses: actions/cache/save@v6
with:
Expand Down
14 changes: 14 additions & 0 deletions .github/opam-repository/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ReScript opam overrides

This repository contains narrowly scoped dependency fixes needed by CI before
they are available from the main opam repository.

The Luv 0.5.14 override preserves the ARM64 musl compiler's
`-mno-outline-atomics` requirement while building vendored libuv. Without it,
the static executable fails to link because libuv refers to glibc's internal
`__getauxval` symbol. The patch should be contributed upstream and this
override removed once a fixed Luv release is available.

Luv 0.5.14 also vendors libuv 1.48.0. Evaluating and contributing an update to
a current libuv 1.x release is a separate upstream follow-up; changing the
vendored library is intentionally outside the OCaml rewatch port.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--- a/src/c/dune
+++ b/src/c/dune
@@ -82,8 +82,14 @@
(action (progn
(bash "cp -r vendor/configure/* vendor/libuv/")
(chdir vendor/libuv (progn
(bash
- "sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \
- 'CC=%{cc}' CFLAGS=-DNDEBUG --silent --enable-silent-rules")
+ "architecture=`ocamlc -config-var architecture`
+ c_compiler=`ocamlc -config-var c_compiler`
+ extra_cflags=
+ case \"$architecture:$c_compiler\" in
+ arm64:*musl*) extra_cflags=-mno-outline-atomics ;;
+ esac
+ sh configure --host `ocamlc -config | awk '/^host:/ {print $NF}'` \
+ 'CC=%{cc}' CFLAGS=\"-DNDEBUG $extra_cflags\" --silent --enable-silent-rules")
(ignore-outputs (bash
"$([ '%{os_type}' = Unix ] && echo %{make} || echo make) V=0 -j 4 \
-o aclocal.m4 -o Makefile.in -o configure \
42 changes: 42 additions & 0 deletions .github/opam-repository/packages/luv/luv.0.5.14/opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
opam-version: "2.0"
name: "luv"
version: "0.5.14"
synopsis: "Binding to libuv: cross-platform asynchronous I/O"
description: """\
Luv is a binding to libuv, the cross-platform C library that does
asynchronous I/O in Node.js and runs its main loop.

Besides asynchronous I/O, libuv also supports multiprocessing and
multithreading. Multiple event loops can be run in different threads. libuv also
exposes a lot of other functionality, amounting to a full OS API, and an
alternative to the standard module Unix."""
maintainer: "Anton Bachin <antonbachin@yahoo.com>"
authors: "Anton Bachin <antonbachin@yahoo.com>"
license: "MIT"
homepage: "https://github.com/aantron/luv"
doc: "https://aantron.github.io/luv"
bug-reports: "https://github.com/aantron/luv/issues"
depends: [
"base-unix" {build}
"ctypes" {>= "0.14.0"}
"dune" {>= "2.7.0"}
"ocaml" {>= "4.03.0"}
"alcotest" {with-test & >= "0.8.1"}
"base-unix" {with-test}
"odoc" {with-doc & = "2.4.0"}
]
build: ["dune" "build" "-p" name "-j" jobs]
patches: ["arm64-musl-outline-atomics.patch"]
extra-files: [
[
"arm64-musl-outline-atomics.patch"
"sha256=c15c4c4d34c9b545197c5160e19c69a128cc186b65a54e0e9a779c2543528a4f"
]
]
dev-repo: "git+https://github.com/aantron/luv.git"
url {
src:
"https://github.com/aantron/luv/releases/download/0.5.14/luv-0.5.14.tar.gz"
checksum:
"sha256=8e01b4a50c8876cdd98d8e245c0687c4dc4d883aed161ad9c5ace1fb1fdaae99"
}
1 change: 1 addition & 0 deletions .github/opam-repository/repo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
opam-version: "2.0"
62 changes: 60 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ jobs:
dune-profile: release

# Verify that the compiler still builds with the oldest OCaml version we support.
# Steps comparing OCaml and Rust rewatch are skipped on this job; the
# first linux-x64 job runs them.
- os: ubuntu-24.04
ocaml_compiler: ocaml-variants.5.0.0+options,ocaml-option-static
node-target: linux-x64
Expand Down Expand Up @@ -215,8 +217,64 @@ jobs:
run: echo "C:\Program Files\Git\bin" >> $GITHUB_PATH
shell: bash

- name: Run rewatch tests
run: ./rewatch/tests/suite.sh rewatch/target/release/rescript
- name: Run OCaml rewatch parity tests
if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }}
timeout-minutes: 20
run: |
bash rewatch-ocaml/tests/check_canonical_test_coverage.sh
bash rewatch-ocaml/tests/check_config_acceptance.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
bash rewatch-ocaml/tests/check_command_validation.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch interactive output tests
# Terminal rendering depends on the host OS, not the CPU architecture.
# Use the faster ARM runners for one Linux and one macOS check. Windows
# does not provide a reliable native equivalent of the `script` PTY.
if: matrix.node-target == 'linux-arm64' || matrix.node-target == 'darwin-arm64'
timeout-minutes: 15
run: |
bash rewatch-ocaml/tests/check_interactive_output.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch verbose output tests
if: ${{ !contains(matrix.ocaml_compiler, '5.0.0') }}
timeout-minutes: 10
run: |
bash rewatch-ocaml/tests/check_verbose_output.sh \
packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe \
packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch unit tests
timeout-minutes: 10
run: |
opam exec -- dune build tests/rewatch_ounit_tests/rewatch_ounit_tests_main.exe
# Run the executable directly so a stuck test leaves live progress;
# dune otherwise buffers the test output until the action exits.
opam exec -- ./_build/default/tests/rewatch_ounit_tests/rewatch_ounit_tests_main.exe -runner sequential
shell: bash

- name: Run OCaml rewatch focused integration tests
timeout-minutes: 30
run: |
sh rewatch-ocaml/tests/run.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

- name: Run OCaml rewatch canonical tests
run: ./rewatch/tests/suite.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript.exe
shell: bash

# The Rust implementation is kept for comparison. One platform runs its
# shared suite; the parity steps exercise it on every platform.
- name: Run Rust rewatch reference tests
if: matrix.node-target == 'linux-arm64'
run: ./rewatch/tests/suite.sh packages/@rescript/${{ matrix.node-target }}/bin/rescript-rust.exe
shell: bash

- name: Run syntax benchmarks
Expand Down
11 changes: 7 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ The Makefile’s targets build on each other in this order:

1. `yarn-install` runs automatically for targets that need JavaScript tooling (lib, playground, tests, formatting, etc.).
2. `build` (default target) builds the toolchain binaries (all copied into `packages/@rescript/<platform>/bin`):
- `compiler` builds the dune executables (`bsc`, `rescript-*`, `ounit_tests`, etc.).
- `rewatch` builds the Rust-based ReScript build system and CLI.
- `compiler` builds the dune executables (`bsc`, `rescript-*`, `ounit_tests`, etc.), including the OCaml build system and CLI (`rescript`).
- `rewatch` builds the Rust implementation of the build system (`rescript-rust`).
3. `lib` uses those toolchain outputs to build the runtime sources.
4. Test targets (`make test`, `make test-syntax`, etc.) reuse everything above.

## Area guidance

Before changing a subsystem, read its local agent instructions and area guide.
For compiler changes, read [compiler/AGENTS.md](compiler/AGENTS.md). For build
system changes, read [rewatch/AGENTS.md](rewatch/AGENTS.md). These apply even
system changes, read [rewatch-ocaml/AGENTS.md](rewatch-ocaml/AGENTS.md) for the
OCaml implementation and [rewatch/AGENTS.md](rewatch/AGENTS.md) for the Rust
one. These apply even
when the task starts at the repository root. Changes spanning areas need the
relevant guidance from each.

Expand All @@ -45,7 +47,8 @@ relevant guidance from each.
- [`compiler/core/README.md`](compiler/core/README.md) for Lambda
optimization and JavaScript generation
- [`analysis/README.md`](analysis/README.md) for editor analysis
- [`rewatch/README.md`](rewatch/README.md) for the build system
- [`rewatch-ocaml/README.md`](rewatch-ocaml/README.md) and
[`rewatch/README.md`](rewatch/README.md) for the build system
- [`tools/README.md`](tools/README.md) for `rescript-tools`

## Coding guidelines
Expand Down
20 changes: 13 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ $(YARN_INSTALL_STAMP): $(YARN_INSTALL_SOURCES)

REWATCH_SOURCES = $(shell find rewatch/src -name '*.rs') rewatch/Cargo.toml rewatch/Cargo.lock
RESCRIPT_EXE = $(BIN_DIR)/rescript.exe
RESCRIPT_RUST_EXE := $(BIN_DIR)/rescript-rust.exe
PACKAGED_RUST_EXE := $(RESCRIPT_RUST_EXE)
ifdef CI
REWATCH_PROFILE := release
REWATCH_CARGO_FLAGS := --release
Expand All @@ -88,22 +90,22 @@ else
endif
REWATCH_TARGET := rewatch/target/$(REWATCH_PROFILE)/rescript$(PLATFORM_EXE_EXT)

rewatch: $(RESCRIPT_EXE)
rewatch: $(PACKAGED_RUST_EXE)

$(RESCRIPT_EXE): $(REWATCH_TARGET)
$(PACKAGED_RUST_EXE): $(REWATCH_TARGET)
$(call COPY_EXE,$<,$@)

$(REWATCH_TARGET): $(REWATCH_SOURCES)
cargo build --manifest-path rewatch/Cargo.toml $(REWATCH_CARGO_FLAGS)

clean-rewatch:
cargo clean --manifest-path rewatch/Cargo.toml && rm -rf rewatch/target && rm -f $(RESCRIPT_EXE)
cargo clean --manifest-path rewatch/Cargo.toml && rm -rf rewatch/target && rm -f $(PACKAGED_RUST_EXE)

# Compiler

COMPILER_SOURCE_DIRS := compiler tests analysis tools
COMPILER_SOURCES = $(shell find $(COMPILER_SOURCE_DIRS) -type f \( -name '*.ml' -o -name '*.mli' -o -name '*.dune' -o -name dune -o -name dune-project \))
COMPILER_BIN_NAMES := bsc rescript-editor-analysis rescript-tools
COMPILER_SOURCE_DIRS := compiler tests analysis tools rewatch-ocaml
COMPILER_SOURCES = $(shell find $(COMPILER_SOURCE_DIRS) -type f \( -name '*.ml' -o -name '*.mli' -o -name '*.c' -o -name '*.h' -o -name '*.dune' -o -name dune -o -name dune-project \))
COMPILER_BIN_NAMES := bsc rescript-editor-analysis rescript-tools rescript
COMPILER_EXES := $(addsuffix .exe,$(addprefix $(BIN_DIR)/,$(COMPILER_BIN_NAMES)))

compiler: $(COMPILER_EXES)
Expand Down Expand Up @@ -279,9 +281,13 @@ COVERAGE_TEST_ENV := BISECT_FILE=$(COVERAGE_BISECT_PREFIX) BISECT_SILENT=YES
.PHONY: coverage-build
coverage-build: | $(YARN_INSTALL_STAMP)
dune build --instrument-with bisect_ppx
@$(foreach bin,$(COMPILER_BIN_NAMES), \
@$(foreach bin,$(filter-out rescript,$(COMPILER_BIN_NAMES)), \
cp $(DUNE_BIN_DIR)/$(bin)$(PLATFORM_EXE_EXT) $(BIN_DIR)/$(bin).exe && \
chmod 755 $(BIN_DIR)/$(bin).exe;)
ifneq ($(OS),Windows_NT)
cp _build/default/rewatch-ocaml/rescript_ocaml.exe $(RESCRIPT_EXE)
chmod 755 $(RESCRIPT_EXE)
endif

.PHONY: coverage-prepare
coverage-prepare: clean-coverage coverage-build
Expand Down
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"!**/tests/tests/**/src",
"!**/tests/tools_tests/**/src",
"!**/rewatch",
"!**/rewatch-ocaml",
"!**/lib/es6",
"!**/lib/js",
"!**/lib/bs",
Expand Down
1 change: 1 addition & 0 deletions changes/ocaml-rewatch-strict-config.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- The OCaml build system rejects duplicate keys in `rescript.json` maps, a `namespace-entry` without a namespace, and a value after `--no-timing`. https://github.com/rescript-lang/rescript/pull/8780
1 change: 1 addition & 0 deletions changes/ocaml-rewatch.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `rescript` now runs a build system rewritten in OCaml; the Rust implementation remains available as `rescript-rust`. https://github.com/rescript-lang/rescript/pull/8780
1 change: 1 addition & 0 deletions cli/common/bins.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ exports.rescript_editor_analysis_exe = path.join(
);
exports.rescript_tools_exe = path.join(binDir, "rescript-tools.exe");
exports.rescript_exe = path.join(binDir, "rescript.exe");
exports.rescript_rust_exe = path.join(binDir, "rescript-rust.exe");

function checkNodeVersionSupported() {
if (
Expand Down
1 change: 1 addition & 0 deletions cli/common/bins.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export {
bsc_exe,
rescript_editor_analysis_exe,
rescript_exe,
rescript_rust_exe,
rescript_tools_exe,
} from "./bins.cjs";
72 changes: 72 additions & 0 deletions cli/common/runBuildSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// @ts-check

import * as child_process from "node:child_process";
import { runtimePath } from "./runtime.js";

/** @type {Record<string, number>} */
const signalToNumber = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGQUIT: 3 };

/**
* Run a build-system executable with the package runtime and forward terminal
* signals so watch mode can clean up before the Node launcher exits.
*
* @param {string} executable
*/
export function runBuildSystem(executable) {
const child = child_process.spawn(executable, process.argv.slice(2), {
stdio: "inherit",
env: { ...process.env, RESCRIPT_RUNTIME: runtimePath },
});

let forwardedSignal = false;
/** @param {NodeJS.Signals} signal */
const handleSignal = signal => {
if (forwardedSignal) return;
forwardedSignal = true;
// Ctrl+C is delivered to every process attached to the Windows console.
// child.kill("SIGINT") uses TerminateProcess there and can kill the build
// system before its console handler releases locks and owned descendants.
if (process.platform === "win32" && signal === "SIGINT") return;
try {
if (child.exitCode === null && child.signalCode == null) {
child.kill(signal);
}
} catch {
// Signal forwarding is best effort if the child exited concurrently.
}
};

process.on("SIGINT", handleSignal);
process.on("SIGTERM", handleSignal);
process.on("SIGHUP", handleSignal);
process.on("SIGQUIT", handleSignal);

process.on("exit", () => {
if (child.exitCode === null && child.signalCode == null) {
try {
child.kill("SIGTERM");
} catch {
// The child may already have exited.
}
}
});

child.on("exit", (code, signal) => {
process.removeListener("SIGINT", handleSignal);
process.removeListener("SIGTERM", handleSignal);
process.removeListener("SIGHUP", handleSignal);
process.removeListener("SIGQUIT", handleSignal);

if (signal) {
const number = signalToNumber[signal];
process.exit(typeof number === "number" ? 128 + number : 1);
} else {
process.exit(typeof code === "number" ? code : 0);
}
});

child.on("error", error => {
console.error(error?.message ?? String(error));
process.exit(1);
});
}
8 changes: 8 additions & 0 deletions cli/rescript-rust.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node

// @ts-check

import { rescript_rust_exe } from "./common/bins.js";
import { runBuildSystem } from "./common/runBuildSystem.js";

runBuildSystem(rescript_rust_exe);
Loading
Loading