5 releases

0.2.0 Sep 16, 2021
0.1.3 Oct 21, 2020
0.1.2 Oct 6, 2020
0.1.1 Oct 3, 2020
0.1.0 Oct 2, 2020

#964 in Parser implementations

Download history 65/week @ 2024-07-04 88/week @ 2024-07-11 135/week @ 2024-07-18 182/week @ 2024-07-25 88/week @ 2024-08-01 72/week @ 2024-08-08 64/week @ 2024-08-15 51/week @ 2024-08-22 117/week @ 2024-08-29 84/week @ 2024-09-05 75/week @ 2024-09-12 93/week @ 2024-09-19 77/week @ 2024-09-26 67/week @ 2024-10-03 39/week @ 2024-10-10 22/week @ 2024-10-17

217 downloads per month
Used in 7 crates (3 directly)

MIT license

290KB
6.5K SLoC

RSLint

A fast, customizable, and easy to use JavaScript and TypeScript linter

build status Documentation Status

Guide | Contributing | Website | Linter Rules

⚠️ RSLint is in early development and should not be used in production, expect bugs! 🐛

Installation

Through Cargo

$ cargo install rslint_cli
$ rslint --help

Prebuilt Binaries

We publish prebuilt binaries for Windows, Linux, and MacOS for every release which you can find here.

Build From Source

$ git clone https://github.com/rslint/rslint.git
$ cd rslint
$ cargo run --release -- --help

Usage

To use the linter simply pass files to lint to the CLI:

$ echo "let a = foo.hasOwnProperty('bar');" > foo.js
$ rslint ./foo.js
error[no-prototype-builtins]: do not access the object property `hasOwnProperty` directly from `foo`
  ┌─ ./foo.js:1:9
  
1 │ let a = foo.hasOwnProperty('bar');
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  
help: get the function from the prototype of `Object` and call it
  
1 │ let a = Object.prototype.hasOwnProperty.call(foo, 'bar');
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
   note: the method may be shadowed and cause random bugs and denial of service vulnerabilities

Outcome: 1 fail, 0 warn, 0 success

help: for more information about the errors try the explain command: `rslint explain <rules>`

The RSLint CLI works without a configuration file and will select recommended non-stylistic rules to run.

Features

Speed. RSLint uses parallelism to utilize multiple threads to speed up linting on top of being compiled to native code.

Low memory footprint. RSLint's syntax tree utilizes interning and other ways of drastically reducing memory usage while linting.

Sensible defaults. The CLI assumes recommended non-stylistic rules if no configuration file is specified and ignores directories such as node_modules.

Error recovery. RSLint's custom parser can recover from syntax errors and produce a usable syntax tree even when whole parts of a statement are missing. Allowing accurate on-the-fly linting as you type.

No confusing options. ECMAScript version for the parser does not have to be configured, the parser assumes latest syntax and assumes scripts for *.js and modules for *.mjs.

Native TypeScript support. *.ts files are automatically linted, no configuration for different parsers or rules is required.

Rule groups. Rules are grouped by scope for ease of configuration, understanding, and a cleaner file structure for the project.

Understandable errors. Each error emitted by the linter points out the area in the source code in an understandable and clean manner as well as contains labels, notes, and suggestions to explain how to fix each issue. There is also an alternative formatter similar to ESLint's formatter available using the -F flag or the formatter key in the config.

Strongly typed rule configuration. RSLint ships a JSON schema and links it for rslintrc.json to provide autocompletion for the config file in Visual Studio Code. The JSON Schema describes rule config options in full, allowing easy configuration. Moreover, RSLint's language server protocol implementation provides autocompletion for rslintrc.toml files too.

Powerful directives. Directives (commands through comments) use a parser based around the internal JavaScript lexer with instructions, allowing us to provide:

  • Autocompletion for directives such as // rslint-ignore no-empty in the language server protocol.
  • Hover support for directives to offer information on a command on hover.
  • Understandable errors for incorrect directives.

Standalone. RSLint is compiled to a single standalone binary, it does not require Node, v8, or any other runtime. RSLint can run on any platform which can be targeted by LLVM.

Powerful autofix. Automatic fixes for some errors are provided and can be applied through the --fix flag or actions in the IDE. Fixes can even be applied if the file contains syntax errors through the --dirty flag.

Built-in documentation. RSLint contains rule documentation in its binary, allowing it to show documentation in the terminal through the explain subcommand, e.g. rslint explain no-empty, for-direction.

Internal Features

Clean and clear project layout. The RSLint project is laid out in a monorepo and each crate has a distinct job, each crate can be used in other Rust projects and each crate has good documentation and a good API.

Easy rule declaration. Rules are declared using a declare_lint! macro. The macro accepts doc comments, a struct name, the group name, a rule code, and configuration options. The macro generates a struct definition and a Rule implementation and processes the doc comments into the documentation for the struct as well as into a static string used in the docs() method on each rule. Everything is concise and kept in one place.

Full fidelity syntax tree. Unlike ESTree, RSLint's custom syntax tree retains:

  • All whitespace
  • All comments
  • All tokens

Allowing it to have powerful analysis without having to rely on separate structures such as ESLint's SourceCode.

Untyped Syntax Tree. RSLint's syntax tree is made of untyped nodes and untyped tokens at the low level, this allows for powerful, efficient traversal through the tree, e.g. if_stmt.cons()?.child_with_ast::<SwitchStmt>().

Easy APIs. RSLint uses easy to use builders for its complex errors, as well as builders for autofix. Everything is laid out to minimize the effort required to implement rules.

Performance

The benchmarks can be found in the benchmarks directory. You can run them on your machine using deno run -A --quiet benchmarks/bench.ts. They are also run on CI and you can see the latest results if you click on the latest GitHub Actions run.

Project RSLint eslint
engine262 (~42k LOC JavaScript) 414ms 46.9s
Oak (~11k LOC TypeScript) 53ms 399ms

(These benchmarks are run on AMD Ryzen 7 2700x, 8 Cores at 3.9MHz)

License

This project is Licensed under the MIT license.


lib.rs:

An extremely fast, lookup table based, ECMAScript lexer which yields SyntaxKind tokens used by the rslint_parse parser.
For the purposes of error recovery, tokens may have an error attached to them, which is reflected in the Iterator Item.
The lexer will also yield COMMENT and WHITESPACE tokens.

The lexer operates on raw bytes to take full advantage of lookup table optimizations, these bytes must be valid utf8, therefore making a lexer from a &[u8] is unsafe since you must make sure the bytes are valid utf8. Do not use this to learn how to lex JavaScript, this is just needlessly fast and demonic because i can't control myself :)

basic ANSI syntax highlighting is also offered through the highlight feature.

Warning ⚠️

>> and >>> are not emitted as single tokens, they are emitted as multiple > tokens. This is because of TypeScript parsing and productions such as T<U<N>>

Dependencies

~2.5–9.5MB
~87K SLoC