Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News RSLint, a New, Fast JavaScript Linter Written in Rust

RSLint, a New, Fast JavaScript Linter Written in Rust

This item in japanese

Riccardo D'Ambrosio recently released RSLint, a linter for JavaScript that is written entirely in Rust. RSLint strives to be as fast as possible, customizable, and easy to use. RSLint is still in the early phase of its development and features basic Visual Studio Code integration.

RSLint’s creator described his motivation as follows:

The project is a fully-fledged JavaScript linter but written from scratch in Rust. I felt existing linters were too limiting and slow and decided to try and make one myself with some key points in mind:

  • speed: file loading, file linting, and rule running are all parallelized
  • very rustc-like and friendly errors (including labels, notes)
  • error recovery: source code can be linted no matter how wrong it is
  • […]
  • more powerful directives

As any linter, RSLint strives to help developers enforce good practices and flag programming errors, bugs, stylistic errors, and suspicious constructs. Linters are generally used within a code editor to provide real-time feedback while editing. Users working on a large codebase with a sizable number of configured lint rules may benefit from the provided speed improvement in the form of faster real-time feedback.

Similarly, developer experience may be enhanced by friendly and explanatory message errors when a lint rule fails, especially so when rules are complex or refer to several other syntactic entities.

D'Ambrosio emphasized the error recovery capabilities of RSLint that are allegedly absent from some known linters:

Error recovery refers to a parser being able to take in incorrect source code, and still parse a mostly correct AST (Abstract Syntax Tree) out of it. Most linters do not attempt this at all, for example, espree, and swc_ecmascript (ESLint and deno_lint’s parsers respectively) make no attempt at recovery. When the parsers encounter an error they return an Err result and quit parsing, producing no AST.
[…] This means it is impossible for the linters to lint wrong code, which is an amazing feature for on-the-fly linting in things such as IDEs.

RSLint can parse the following code:

if true {
  /* */
} else {
  /* */

and lints it as follows:

error[SyntaxError]: Expected token `L_PAREN` but instead found `TRUE_KW`
  ┌─ tests\main.js:1:4
1 │ if true {
  │    ^^^^ Unexpected

error[SyntaxError]: Expected token `R_PAREN` but instead found `L_CURLY`
  ┌─ tests\main.js:1:9
1 │ if true {
  │         ^ Unexpected

error[no-constant-condition]: Unexpected constant condition
  ┌─ tests\main.js:1:4
1 │   if true {
  │      ^^^^ this condition is always truthy...
2 │     /* */
3 │   } else {
  │ ┌────────'
4 │ │   /* */
5 │ │ }
  │ └─' ...which makes this unreachable

D'Ambrosio however recalled the early-stage nature of the project:

Note however that rslint_parser is still in early development, and error recovery can be buggy and explosive at times, this will get better in the future however.

RSLint achieves its speed not only by being written in Rust, that is, compiled to machine code; but also by parallelizing tasks and relying on a specific data structure rather than the customary AST. RSLint uses the rowan Rust library that was developed for the Rust analyzer project. Rowan models trees as immutable syntax trees, instead of mutable AST that are expensive to clone.

RSLint provides a few directives that allow developers to ignore entire files when linting, or ignore specific lint rules in some context (rslint-ignore). RSLint currently implements around 25 rules (e.g., no-async-promise-executor, no-await-in-loop, or no-dupe-keys), with more planned in the future. Developers can write custom rules. However, according to the documentation, custom rules must be written with Rust macros — a possible barrier to contributions by the JavaScript community.

RSLint is part of an emerging trend consisting of writing JavaScript tooling in other languages that compile to native code. InfoQ previously reported on the JavaScript bundler esbuild written in Go. swc is a Rust-based JavaScript/TypeScript compiler. That trend is driven by the quest for raw performance to shorten feedback cycles of JavaScript tooling, and take advantage of the power multi-core capabilities of developers’ machines.

Writing code in compile-to-native languages is not however the only way to achieve higher throughput. Tooling can be made faster by reducing the scope of the automated tasks. The Sucrase JavaScript/TypeScript compiler beat the Rust-based swc compiler on some benchmarks last year. Sucrase however targets only development builds, and makes some restrictive assumptions (e.g., no support for Node 6 or Internet Explorer).

Some members of the JavaScript community have been cautiously optimistic on Reddit regarding RSLint. One user mentioned:

This is awesome! Still early stages but great work, looking forward to seeing how this project progresses!

Another one enumerated a few important features for adoption by the community:

Hey so this looks great. I’d love to be able to speed up linting. In order to use this at work, it’d need to be pretty mature/feature complete and come with reasonable reassurances about ongoing maintenance.

RSLint is currently heavily developed and in its early stage. RSLint roadmap includes benchmarking, scope analysis, autofix, JSX and TypeScript support, JavaScript plugins, and more. Known issues and documentation are available online.

RSLint is open-sourced under the MIT license. Contributions and pull requests are welcome through the project’s GitHub repository.

Rate this Article