I'm looking into using ast-grep fo linting ReScript. What rules should I investigate?

Amazing! Do you think that can that somehow be integrated in the editor-tooling?

Probably? I think the first step is getting a separate NPM package published that can handle linting with the existing ast-grep plugin and from the command line, then getting a handful of rules into it that are useful.

1 Like

As long as there’s some way to produce error mesages with locations, integrating into the editor tooling should be doable.

1 Like

The existing ast-grep plugin does that and works with what we have so far for ReScript.

1 Like

I spent last night integrating it into flychecker for emacs, so if we prefer to integrate it into the main tooling, I can confirm that ast-grep scan --report-style short <source-file> gives usable plaintext output.

2 Likes

I managed to get it working! Now I have a portable package that can init itself based on a toplevel config, and it sets the vscode extension config to use the ast-grep config in the node_modules linter folder!

Any objections to me publishing it as rescript-lint? If something better comes along I have no issues surrendering the package.

2 Likes

I just need to get it all running from node_modules now. I have the vscode extension showing warnings, but the CLI isn’t running. This is fun lol.

I have it running on Node 20, but I’m struggling with Node 22.

This works on node 20:

sg scan --config "./node_modules/rescript-lint/sgconfig.yml" src
warning[no-console]: Unexpected console statement.
  ┌─ src/index.res:2:3
  │
2 │   Console.log("foo!")
  │   ^^^^^^^
  │
  = Remove the console statement.

But on node 22:

sg: group 'scan' does not exist
1 Like

Of note: as far as I can tell, there’s not a way to track individual variables with ast-grep, so I don’t think we’d be able to use it for, say, checking dependency arrays. I might play around with using tree-sitter directly.

Still looking for ideas?

In our codebase we sometimes make use of Obj.magic(x), typically when dealing with JSON or js interop in an area we don’t care that much to do strict decoding

Sometimes though the type resolves to something unexpected and then the error is hard to trace.

A useful lint rule would be to require obj.magic to always specify the type you are expecting to cast it to

let x = Obj.magic(1) // lint error!

let x: int = Obj.magic(1) // Ok!
let x = (Obj.magic(1) : int) // Ok!
2 Likes