Skip to content

Experimental ReScript Language Server in OCaml - #8425

Open
aspeddro wants to merge 189 commits into
rescript-lang:masterfrom
aspeddro:lsp
Open

aspeddro wants to merge 189 commits into
rescript-lang:masterfrom
aspeddro:lsp

Conversation

@aspeddro

@aspeddro aspeddro commented May 14, 2026 •

Copy link
Copy Markdown
Contributor

This branch introduces a ReScript LSP server built on top of the existing
analysis library. It runs in-process through rescript lsp --stdio, using the
new rescript CLI written in OCaml (rewatch-ocaml). There is no separate
rescript-language-server executable. It's a separate, OCaml-side exploration
alongside the Rust/rewatch-based experiment in #8243, the two share the same
goal (a LSP server for ReScript) but approach it from different ends of the
toolchain.

Why rewriting the server in OCaml is a good fit

The editor features are already implemented in the OCaml analysis library.
Hover, completion, references, rename, document symbols, code actions, and
diagnostics all depend on compiler data structures such as .cmt / .cmti,
typed trees, locations, package metadata, and compiler diagnostics. Running the
LSP server in OCaml lets the server call those APIs directly instead of shelling
out to rescript-editor-analysis.exe or passing JSON through stdin. That
removes a large amount of process orchestration and serialization glue, and
keeps the LSP closer to the compiler types it needs to understand. This also
makes the server easier to evolve with the compiler. When typedtree, diagnostic
formats, package discovery, or .cmt handling changes, the LSP can be updated
in the same language and build system as the analysis code. That reduces version
skew and makes bugs easier to reproduce with Dune/expect tests.

Why ship the language server with the compiler

The language server is tightly coupled to the compiler version used by a
project. It reads .cmt and .cmti files containing marshalled compiler
internals such as Typedtree, Types, and Env. These files are not a stable,
schema-aware protocol: changing one of those OCaml types can make an analysis
binary incompatible with artifacts produced by another compiler revision.

This is not only a theoretical compatibility concern. In
#8475, adding typedtree
constructors for for...of without changing the CMT magic number allowed a
newer analysis binary to read incompatible ReScript 12 artifacts and
segmentation fault. The same class of failure appeared after record-rest changes
altered compiler data stored in CMT files. Bumping the CMT magic number makes
these mismatches rejectable, but the project must still be rebuilt with the
matching compiler.

Shipping the server in the same platform package as the compiler, and exposing
it through rescript lsp --stdio, gives clients one project-local entrypoint.
The selected ReScript dependency then supplies bsc, the analysis code, and the
language server from the same release. This has several practical benefits:

  • Editors do not need to install or select a separate language-server version.
  • Projects pinned to different ReScript versions get the corresponding server.
  • Compiler, analysis, and LSP changes can be released and upgraded atomically.
  • The OCaml rescript executable links the server library directly, so no
    separate language-server executable needs to be located or launched.

Bundling does not make stale artifacts safe. Compiler changes that alter
marshalled CMT data must still bump the magic number, and the server should turn
version mismatches into an actionable request to rebuild. A separately versioned
server becomes practical only if analysis moves to a stable, explicitly
versioned artifact format or maintains decoders for multiple compiler-internal
formats. Until then, promising one server binary that supports multiple compiler
versions would hide a compatibility boundary that already exists.

What's here

  • The server library lives in lsp/src, with its own opam package
    (rescript-language-server.opam). It uses lsp (>= 1.22.0), eio,
    ppx_deriving_yojson, ppx_expect and the in-tree analysis library.
  • The entrypoint is rewatch-ocaml/rescript_ocaml.ml. The OCaml rescript
    executable links the server library and uses Eio_main.run to supply its
    filesystem, stdin and stdout.
  • Start the server with rescript lsp --stdio. The --stdio flag is required:
    rescript lsp without it fails and displays usage help. The LSP subcommand
    does not accept --quiet or --verbose.
  • End-to-end snapshot tests in tests/lsp_tests exercise the server through the
    same OCaml CLI entrypoint.

Status / what's not here yet

The main objective is to first maintain feature parity with the current server
(server.ts) as much as possible. Below is a list of some requests and
notifications. Some are out of scope because they don't make sense.

  • initialize - client request
  • initialized - client notification
  • shutdown - client request
  • exit - client notification
  • textDocument/didOpen - client notification
  • textDocument/didChange - client notification
    • Incremental change
  • textDocument/didClose - client notification
  • textDocument/didSave - client notification - It will not be
    implemented for now.
  • textDocument/hover - client request
  • textDocument/publishDiagnostics - server notification
    • More work was needed for some kinds of errors. How should circular
      dependency errors be published?
      • Circular dependency diagnostics are special-cased because the compiler log
        does not point at a precise source range. When the document is open, we
        expand the diagnostic range to cover the whole document so the editor can
        display a file-level diagnostic. If the document is not open, we keep the
        range parsed from the compiler log, i.e.,
        {start: {line: 0, character: 0}, end: {line: 0, character: 6}}
        • The shortest possible code has at least 7 characters: let a=1.
          Protocol positions are zero-based, so the position is length - 1.
    • Use Analysis for syntax errors and ignore them in the compiler log
      parser.
      • This lets the server publish syntax errors on TextDocumentDidChange and
        provide instant feedback.
    • Compiler-log diagnostics from .compiler.log - server feature
      • Add more test cases; see compiler_log.ml. See tests/build_tests
        for more examples.
    • Monorepo diagnostics via .sourcedirs.json - server feature
      • Requires ReScript v12.1.0. In this version, .sourcedirs.json is always
        generated with build_root field for each subpackage.
    • Add the warning number to the diagnostic message.
  • workspace/didChangeWatchedFiles - client notification
    • The server uses this notification to detect changes to generated
      .compiler.log files, which usually means a ReScript build has finished.
      When a watched log changes, the server re-reads every known compiler log and
      republishes diagnostics so stale errors are cleared and monorepo diagnostics
      stay in sync.
    • Use GlobPattern with baseUri (workspace root)?
    • Should we watch all rescript.json files in the workspace root?
      • Some features require data defined in rescript.json. For example,
        suffix and package-specs are needed to create the code action
        Open compiled JS file. Changes in dependencies impact various
        functionalities because they modify the state in
        Analysis.Shared_types.state.
      • Users can restart the server after changing the configuration.
  • client/registerCapability - server request
    • We use this because workspace/didChangeWatchedFiles is commonly registered
      dynamically. The server does not know all file-watch patterns during the
      static initialize response. In this LSP, the watcher list depends on
      project state, especially .sourcedirs.json, which tells us where each
      ReScript build root lives. In monorepos, that means the server needs to
      register watchers for compiler logs after initialization, once it has
      workspace context. That means watching generated .compiler.log files. When
      the client sees one change, it sends workspace/didChangeWatchedFiles, and
      the server refreshes diagnostics.
  • textDocument/diagnostic - client request
  • textDocument/completion - client request
  • completionItem/resolve - client request
  • textDocument/signatureHelp - client request
  • textDocument/definition - client request
  • textDocument/declaration - client request - It will not be implemented
    for now.
  • textDocument/typeDefinition - client request
  • textDocument/implementation - client request - It will not be
    implemented for now.
  • textDocument/references - client request
  • textDocument/documentHighlight - client request - It will not be
    implemented for now.
  • textDocument/documentSymbol - client request
    • Zed needs the "document_symbols": "on" configuration. When enabled,
      tree-sitter is not used for document symbols.
  • workspace/symbol - client request - It will not be implemented for
    now.
  • textDocument/codeAction - client request
    • Code actions from analysis
    • Code actions from diagnostics (refactor, quick fixes, etc)
    • Open compiled js file (Trigger workspace execute command
      rescript/openCompiled)
      • Available if the client supports window/showDocument.
    • Create interface file (Trigger workspace execute command
      rescript/createInterface)
      • Available if the interface does not exist.
    • Switch to implementation/interface (Trigger workspace execute command
      rescript/switchImplementationInterface)
      • Available if the client supports the window/showDocument request.
  • codeAction/resolve - client request - It will not be implemented for
    now.
  • textDocument/codeLens - client request
  • workspace/codeLens/refresh - server request
  • codeLens/resolve - client request - It will not be implemented for
    now.
  • textDocument/inlayHint - client request
  • inlayHint/resolve - client request - It will not be implemented for
    now.
  • textDocument/semanticTokens/full - client request
  • textDocument/semanticTokens/full/delta - client request - It will not
    be implemented for now.
  • textDocument/semanticTokens/range - client request - It will not be
    implemented for now.
  • textDocument/rename - client request
  • textDocument/prepareRename - client request
  • textDocument/formatting - client request
  • textDocument/rangeFormatting - client request - It will not be
    implemented for now.
  • textDocument/onTypeFormatting - client request - It will not be
    implemented for now.
  • textDocument/foldingRange - client request - It will not be
    implemented for now.
  • textDocument/selectionRange - client request - It will not be
    implemented for now.
  • textDocument/documentLink - client request - It will not be
    implemented for now.
  • documentLink/resolve - client request - It will not be implemented for
    now.
  • textDocument/documentColor - client request - It will not be
    implemented for now.
  • textDocument/linkedEditingRange - client request - It will not be
    implemented for now.
  • workspace/didChangeConfiguration - client notification
  • workspace/configuration - server request
  • workspace/executeCommand - client request
    • rescript/dumpServerState
      • Dump the State.t (diagnostics, document store, status, configuration,
        analysis state (Analysis.Shared_types.state) and compiler config).
      • Write a temporary .json file and open it using window/showDocument.
        Requires client support for that request; the command returns no content.
    • rescript/openCompiled: Triggered by a code action
      • Only works if the client supports window/showDocument.
    • rescript/createInterface: Triggered by a code action
      • The server creates the interface if it does not exist and opens the
        interface file if the client supports the window/showDocument request.
      • If the interface file already exists, the server sends an error.
    • rescript/switchImplementationInterface: Triggered by a code action
      • Only available if the client supports the window/showDocument request.
    • rescript/dumpCmt: Dump cmt file content
      • Write a temporary .txt file and open it using window/showDocument.
        Requires client support for that request; the command returns no content.
    • rescript/dumpParseTree It will not be implemented for now.
      • Dump parsed tree
    • rescript/dumpTypedTree It will not be implemented for now.
      • Dump typed tree
    • Flow to execute a command:
  • Custom requests
    • textDocument/openCompiled - client request
    • textDocument/createInterface - client request
    • textDocument/switchImplementationInterface: Currently it's done on the
      client side, but it could be a command triggered by a code action.
      • Move to code action feature
    • rescript/startBuild - client request - How the build integration
      will be done. See last point
      . It will not be implemented for now
      • Some questions
        • Create a setting to automatically start the build watcher during
          initialization and drop this custom request?
        • When should the build watcher be stopped? On shutdown/exit?
        • Create work-done progress?
        • Add a custom request to kill the watcher rescript/stopBuild?
  • Custom notifications
  • Channels to support
    • The current server (server.ts) supports stdio and node-ipc. The VSCode
      client uses node-ipc. This implementation supports only stdio.
    • stdio
    • socket - It will not be implemented for now
  • Incremental compilation - server feature - It will
    not be implemented for now.
  • Build integration managed by the LSP server - server feature - It will
    not be implemented for now.
    • Build integration is still external: diagnostics come from compiler logs
      produced by an existing rescript build, rather than the LSP starting or
      managing builds itself.
  • First-class compiler support on the server. It will not be implemented
    for now. Idea to explore.

Tests

tests/lsp_tests/ contains OCaml ppx_expect end-to-end tests, with a named
let%expect_test for each scenario and separate modules for each feature.
Representative cases are adapted from tests/analysis_tests; the original
analysis suite remains in place. Source snippets no longer contain cursor
markers: requests use explicit, zero-based LSP positions.

The shared client in test.ml starts
rewatch-ocaml/rescript_ocaml.exe lsp --stdio through Unix.open_process_args,
avoiding Eio.Stdenv.process_mgr in the test harness so it can run on Windows,
Linux and macOS. Dune declares the CLI executable as a test dependency. The
harness supplies RESCRIPT_RUNTIME because it bypasses the npm launcher.

Tests create their source files and rescript.json from OCaml.
Test.setup_project writes the project and optionally builds it;
Test.with_project manages a temporary workspace and cleanup. Tests can add
multiple documents, edit unsaved buffers, rebuild, change settings and vary
client capabilities. Snapshots normalize temporary workspace paths while
preserving ranges and response ordering.

Coverage includes hover and JSX hover, completion and JSX completion, completion
resolution, definitions, type definitions, references, prepare rename, rename,
document symbols, semantic tokens, signature help, interface creation, code
actions, inlay hints, syntax diagnostics and code lenses. Diagnostic regression
tests cover build-log updates, stale warnings, duplicate publications, flicker
and document closure. Execute-command tests check the temporary state/CMT dump
files and window/showDocument capability handling. These tests do not imply
complete coverage or feature parity with the existing server.

Build the toolchain and runtime and run the LSP suite with:

opam exec -- make test-lsp

After the toolchain and runtime are built, run just the integration suite with
opam exec -- dune runtest tests/lsp_tests. Run opam exec -- dune runtest to
also cover inline tests in the server library, including .sourcedirs.json
build-root extraction and .compiler.log parsing. See
the snapshot test guide for helpers and commands
to review and promote snapshots.

Breaking Changes

Server settings

Proposed interface.

  • Currently (server.ts), supportMarkdownLinks is not a setting. It's a great
    feature, but some clients don't have good support; Neovim are a example.
    Therefore, I'm promoting it to a setting so users can enable or disable it.
/**
 * Server settings.
 * These configurations are requested by the server using `workspace/configuration`.
 */
interface Settings {
  hover?: {
    /**
     * Enable markdown links in hover responses
     * @default false
     */
    supportMarkdownLinks?: boolean;
  };
  /**
   * Enable code lenses for function definitions, showing the full type above each definition
   * @default false
   */
  codeLens?: boolean;
  /**
   * Place annotations inline with text to display type hints
   */
  inlayHints?: {
    /**
     * Enable inlay hints
     * @default false
     */
    enable?: boolean;
    /**
     * Maximum number of characters for inlay hints. Set to null to have an unlimited length.
     * Inlay hints that exceed the maximum length will not be shown
     * @default 25
     */
    maxLength?: number | null;
  };
}

Release and transition plan

How should the server be published? How should developers use the server?

Other related topics

Refactor analysis for use on the server side

  • Parsing from source (not just files) / decouple I/O from core logic
    #8426
    #8466
    #8478
  • Use the yojson and lsp libraries in the analysis library
    ##8436
  • Remove global state Shared_types.state
    #8465

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
- Move Io, Chan, and listen infrastructure to server.ml
- Simplify on_request to take a packed request directly
- Add basic hover response with markdown content
- Rename public executable to rescript-language-server

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
- Add `parse_implementation_from_source` to parsing/print engine types
  and all engine implementations, enabling parsing from a string source
  rather than a filename
- Use `parse_implementation_from_source` in CompletionFrontEnd
- Rename package from `rescript-lsp` to `rescript-language-server`
- Refactor LSP server with typed state, document store, and diagnostics
- Add hover support via completion backend integration

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Move LSP modules under lsp/src/ with a thin lsp/bin/ entry point, add a
configuration module, and introduce a tests/lsp_tests workspace exercising
hover end-to-end.

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Splits `Commands.ml` into a pure layer that returns OCaml values
(option, list, typed records like Protocol.hover,
Protocol.signatureHelp, Protocol.completionItem) and a new
`analysis/src/Cli.ml` that does the stringify-and-print step.
`analysis/bin/main.ml` now dispatches to `Cli.*`, while the LSP server
consumes `Commands.*` directly.

Makes the parsers accept source strings: `res_driver` gains
`parse_interface_from_source` alongside the existing
`parse_implementation_from_source`

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
aspeddro added 2 commits May 22, 2026 10:09
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
@codecov

codecov Bot commented May 22, 2026 •

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

aspeddro added 10 commits May 30, 2026 15:25
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
- Rename Helper module to Client
- Move expected output files into workspace directories
- Improve request log format to show file path:line:col
- Simplify hover.ml by removing intermediate result binding
- Disable in-source compilation for basic-workspace

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Why:
    Projects opened before their first build lack generated metadata.
    Recover on compiler-log events without requiring an editor restart.

Context modified (compiler-log creation and change notifications):
Before (text):
    Refresh diagnostics using the existing analysis and package context.
After (text):
    Discover fresh analysis tables and package configuration.
    Replace the context if the workspace package is available.
    Otherwise retain the previous context without repeated error messages.
    Preserve open buffers, settings and diagnostics, then refresh diagnostics.

Diagnostic modified (initial package discovery failure):
Before (text):
    Try building the project then restart the server
After (text):
    Try building the project. The server will retry when a compiler log
    changes.

Add snapshot tests for Created and Changed events, early retries,
compiled-file lookup and preservation of unsaved buffers. Document the
automatic recovery behavior.

Validation: dune build and eight recovery/diagnostic tests pass. The full LSP
    suite still has snapshot differences in hover_jsx.ml and code_action.ml.
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
aspeddro added a commit to aspeddro/rescript-compiler that referenced this pull request Oct 31, 2026
* Omit empty document symbol children

DocumentSymbol.children is optional, so only set it when a symbol has nested entries. This avoids serializing leaf symbols with an empty children array.

Signed-off-by: Pedro Castro <aspeddro@gmail.com>

* add transform_opt for server-side use

* analysis: add state_to_yojson

* packages: add dependencies

* Update CHANGELOG.md

* Apply codex review suggestions

* Refactor cmt_viewer.dump for serve-side

* Analysis cmt dump return a string instead a option

---------

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Co-authored-by: Florian Hammerschmidt <florianh89@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
changes/opam-ppx-expect.internal.md

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
@aspeddro

Copy link
Copy Markdown
Contributor Author

Codex review using GPT 6 Astra Ultra


The new server has position-encoding and initialization compatibility bugs, incorrect package artifact resolution, and a formatter process leak. These affect ordinary editor workflows and require correction.

Full review comments:

  • [P1] Negotiate position encoding before interpreting document edits — /home/pedro/Desktop/projects/rescript-compiler/lsp/src/document.ml:28-30
    Documents unconditionally interpret positions as UTF-8, but the initialize response omits positionEncoding, which means UTF-16 in LSP. Consequently, edits after non-ASCII characters can modify the wrong bytes or be silently rejected, and analysis locations are misaligned. Negotiate the encoding with the client and convert positions consistently, including supporting the mandatory UTF-16 fallback.

  • [P2] Append the namespace after removing the source extension — /home/pedro/Desktop/projects/rescript-compiler/lsp/src/helpers.ml:131-133
    For a namespaced source such as Test.res, this constructs Test.res-MyPackage and then removes .res-MyPackage, yielding Test.cmi instead of Test-MyPackage.cmi. Interface creation therefore cannot find the compiled interface in namespaced projects. Remove the source extension before appending the namespace suffix.

  • [P2] Select output configuration from the requested document — /home/pedro/Desktop/projects/rescript-compiler/lsp/src/helpers.ml:156-161
    When a document belongs to a discovered dependency or nested package, this selects the workspace root's configuration rather than that document's package configuration. If the packages have different suffixes, module formats, or in-source settings, opening compiled JavaScript looks in the wrong location despite the output existing. Match against Uri.to_path uri here and in the analogous configuration lookup in get_cmi_file.

  • [P2] Accept workspace folders without a legacy root URI — /home/pedro/Desktop/projects/rescript-compiler/lsp/src/helpers.ml:5-6
    A valid initialize request can supply a nonempty workspaceFolders list while leaving the deprecated rootUri and rootPath null. This pattern requires rootUri as well, so such requests fall through to failwith, terminating initialization instead of using the supplied workspace folder. Handle a nonempty folder list independently of the legacy fields.

  • [P2] Validate syntax before spawning the formatter — /home/pedro/Desktop/projects/rescript-compiler/lsp/src/formatter.ml:66-69
    Formatting a document with a syntax error reaches this branch after Unix.open_process_args has already started the formatter, but returns without closing either pipe or reaping the child. Repeated format requests on incomplete code accumulate processes and descriptors. Perform the syntax check before spawning, or guarantee cleanup on this branch too.

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
namespace, producing Test-MyPackage.cmi

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
document's package configuration instead of the workspace root's
settings.

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
independently of rootUri and rootPath. Fallback to Sys.getcwd

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
relying on the ReScript formatter to report syntax errors.

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>
…, configuration, limitations, and test workflow in

Signed-off-by: Pedro Castro <aspeddro@gmail.com>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes analysis prefer the runtime installed in the project over the compiler-local runtime.

Previously, resolving @rescript/runtime bypassed the normal node_modules search and immediately returned Runtime_package.get_path (). During local LSP development, this could make “Go to definition” open runtime sources from the compiler checkout instead of the user’s project.

The resolver now searches the project and its ancestor directories first, including the .deno/node_modules and .pnpm/node_modules lookup locations. The compiler-local runtime remains a fallback for development environments where the project has no runtime installation.

This is not a complete Node/Deno/pnpm module resolver; it extends the existing package-directory lookup. The explicit RESCRIPT_RUNTIME override still takes precedence when selecting the analysis runtime.

Module resolution searches each directory and its ancestors for:

  1. node_modules/<package>
  2. node_modules/.deno/node_modules/<package>
  3. node_modules/.pnpm/node_modules/<package>

Comment thread .github/workflows/ci.yml
# first linux-x64 job runs them.
- os: ubuntu-24.04
ocaml_compiler: ocaml-variants.5.0.0+options,ocaml-option-static
ocaml_compiler: ocaml-variants.5.3.0+options,ocaml-option-static

@aspeddro aspeddro Nov 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI compatibility job now uses OCaml 5.3 instead of 5.0 because the current test dependencies cannot be resolved on 5.0.

The compiler requires ppxlib >= 0.38.0. The language server’s ppx_expect dependency pulls in Jane Street PPXs whose versions compatible with that ppxlib require OCaml 5.3 or newer.

@aspeddro
aspeddro marked this pull request as ready for review November 7, 2026 03:19
JSX, existential hover, record-rest patterns, and namespaced references.

Signed-off-by: Pedro Castro <aspeddro@gmail.com>
Signed-off-by: Pedro Castro <aspeddro@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant