Add ReScript support (#5072)

This adds support for both rescript format and rescript-language-server.

Closes https://github.com/dense-analysis/ale/issues/3335
This commit is contained in:
John Jackson
2025-12-21 04:25:42 -05:00
committed by GitHub
parent dd6e6f1b15
commit 0360a73644
13 changed files with 196 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
" Author: John Jackson <john@johnridesa.bike>
" Description: The official language server for ReScript.
call ale#Set('rescript_language_server_executable', 'rescript-language-server')
call ale#Set(
\ 'rescript_language_server_use_global',
\ get(g:, 'ale_use_global_executables', v:true),
\ )
function! s:GetProjectRoot(buffer) abort
let l:config_file = ale#path#FindNearestFile(a:buffer, 'rescript.json')
return !empty(l:config_file) ? fnamemodify(l:config_file, ':h') : ''
endfunction
call ale#linter#Define('rescript', {
\ 'name': 'rescript_language_server',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#path#FindExecutable(b, 'rescript_language_server', [
\ 'node_modules/.bin/rescript-language-server'
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('s:GetProjectRoot'),
\})

View File

@@ -672,6 +672,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['racket'],
\ 'description': 'Fix Racket files with raco fmt.',
\ },
\ 'rescript_format': {
\ 'function': 'ale#fixers#rescript_format#Fix',
\ 'suggested_filetypes': ['rescript'],
\ 'description': 'Official formatter for ReScript.',
\ },
\ 'ruff': {
\ 'function': 'ale#fixers#ruff#Fix',
\ 'suggested_filetypes': ['python'],

View File

@@ -0,0 +1,33 @@
" Author: John Jackson <john@johnridesa.bike>
" Description: Fix ReScript files with the ReScript formatter.
call ale#Set('rescript_format_executable', 'rescript')
call ale#Set(
\ 'rescript_format_use_global',
\ get(g:, 'ale_use_global_executables', v:false)
\ )
function! s:GetExecutable(buffer) abort
return ale#path#FindExecutable(a:buffer, 'rescript_format', [
\ 'node_modules/.bin/rescript',
\])
endfunction
function! s:FixWithVersion(buffer, version) abort
let l:exe = ale#Escape(s:GetExecutable(a:buffer))
let l:stdin = ale#semver#GTE(a:version, [12, 0, 0]) ? ' --stdin' : ' -stdin'
let l:ext = fnamemodify(bufname(a:buffer), ':e') is? 'resi'
\ ? ' .resi'
\ : ' .res'
return {'command': l:exe . ' format' . l:stdin . l:ext}
endfunction
function! ale#fixers#rescript_format#Fix(buffer) abort
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ s:GetExecutable(a:buffer),
\ '%e --version',
\ function('s:FixWithVersion'),
\)
endfunction

54
doc/ale-rescript.txt Normal file
View File

@@ -0,0 +1,54 @@
===============================================================================
ALE ReScript Integration *ale-rescript-options*
===============================================================================
rescript-language-server *ale-rescript-language-server*
*ale-options.rescript_language_server_executable*
*g:ale_rescript_language_server_executable*
*b:ale_rescript_language_server_executable*
ale_rescript_language_server_executable
g:ale_rescript_language_server_executable
Type: |String|
Default: `'rescript-language-server'`
See |ale-integrations-local-executables|
*ale-options.rescript_language_server_use_global*
*g:ale_rescript_language_server_use_global*
*b:ale_rescript_language_server_use_global*
rescript_language_server_use_global
g:ale_rescript_language_server_use_global
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', v:true)`
See |ale-integrations-local-executables|
===============================================================================
rescript_format *ale-rescript-format*
*ale-options.rescript_format_executable*
*g:ale_rescript_format_executable*
*b:ale_rescript_format_executable*
rescript_format_executable
g:ale_rescript_format_executable
Type: |String|
Default: `'rescript'`
See |ale-integrations-local-executables|
*ale-options.rescript_format_use_global*
*g:ale_rescript_format_use_global*
*b:ale_rescript_format_use_global*
rescript_format_use_global
g:ale_rescript_format_use_global
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', v:false)`
See |ale-integrations-local-executables|
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -582,6 +582,9 @@ Notes:
* `cspell`
* `opacheck`
* `opafmt`
* ReScript
* `rescript-language-server`
* `rescript_format`
* REST
* kulala_fmt
* reStructuredText

View File

@@ -3862,6 +3862,9 @@ documented in additional help files.
cspell................................|ale-rego-cspell|
opacheck..............................|ale-rego-opa-check|
opafmt................................|ale-rego-opa-fmt-fixer|
rescript................................|ale-rescript-options|
rescript-language-server..............|ale-rescript-language-server|
rescript_format.......................|ale-rescript-format|
rest....................................|ale-rest-options|
kulala_fmt............................|ale-rest-kulala_fmt|
restructuredtext........................|ale-restructuredtext-options|

View File

@@ -592,6 +592,9 @@ formatting.
* [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell)
* [opacheck](https://www.openpolicyagent.org/docs/latest/cli/#opa-check)
* [opafmt](https://www.openpolicyagent.org/docs/latest/cli/#opa-fmt)
* ReScript
* [rescript-language-server](https://www.npmjs.com/package/@rescript/language-server) :speech_balloon:
* [rescript_format](https://rescript-lang.org/)
* REST
* [kulala_fmt](https://github.com/mistweaverco/kulala-fmt)
* reStructuredText

View File

@@ -0,0 +1,46 @@
Before:
call ale#assert#SetUpFixerTest('rescript', 'rescript_format')
After:
call ale#assert#TearDownFixerTest()
Execute(The rescript callback should return the correct default values):
call ale#test#SetFilename('../test-files/rescript/testfile-noextension')
set filetype=rescript
GivenCommandOutput ['12.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .res'
\ }
Execute(The rescript callback should correctly detect res files):
call ale#test#SetFilename('../test-files/rescript/testfile.res')
GivenCommandOutput ['12.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .res'
\ }
Execute(The rescript callback should correctly detect resi files):
call ale#test#SetFilename('../test-files/rescript/testfile.resi')
GivenCommandOutput ['12.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .resi'
\ }
Execute(The version check should be correct):
call ale#test#SetFilename('../test-files/rescript/testfile.res')
GivenCommandOutput ['11.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format -stdin .res'
\ }

View File

@@ -0,0 +1,25 @@
Before:
call ale#assert#SetUpLinterTest('rescript', 'rescript_language_server')
Save &filetype
let &filetype = 'rescript'
After:
call ale#assert#TearDownLinterTest()
Execute(The language string should be correct):
AssertLSPLanguage 'rescript'
Execute(The project root should be detected correctly):
AssertLSPProject ''
call ale#test#SetFilename('../test-files/rescript/testfile.res')
AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/rescript')
Execute(The command should be correct):
call ale#test#SetFilename('../test-files/rescript/testfile.res')
AssertLinter
\ 'rescript-language-server',
\ ale#Escape('rescript-language-server') . ' --stdio'

View File

View File

View File