lintspec 0.9.0

A blazingly fast linter for NatSpec comments in Solidity code
Documentation
# 🔎 lintspec

![lintspec screenshot](https://raw.githubusercontent.com/beeb/lintspec/refs/heads/main/screenshot.png)

<div align="center">
  <a href="https://github.com/beeb/lintspec"><img
      alt="github"
      src="https://img.shields.io/badge/github-beeb%2Flintspec-228b22?style=flat&logo=github"
      height="20"
  /></a>
  <a href="https://crates.io/crates/lintspec"><img
      alt="crates.io"
      src="https://img.shields.io/crates/v/lintspec.svg?style=flat&color=e37602&logo=rust"
      height="20"
  /></a>
  <a href="https://docs.rs/lintspec/latest/lintspec/"><img
      alt="docs.rs"
      src="https://img.shields.io/badge/docs.rs-lintspec-3b74d1?style=flat&labelColor=555555&logo=docs.rs"
      height="20"
  /></a>
  <a href="https://docs.rs/lintspec/latest/lintspec/"><img
      alt="MSRV"
      src="https://img.shields.io/badge/MSRV-1.88.0-b83fbf?style=flat&labelColor=555555&logo=docs.rs"
      height="20"
  /></a>
  <a href="https://codspeed.io/beeb/lintspec"><img
      alt="CodSpeed"
      src="https://img.shields.io/endpoint?url=https://codspeed.io/badge.json"
  /></a>
</div>

Lintspec is a command-line utility (linter) that checks the completeness and validity of
[NatSpec](https://docs.soliditylang.org/en/latest/natspec-format.html) doc-comments in Solidity code. It is focused on
speed and ergonomics. By default, lintspec will respect gitignore rules when looking for Solidity source files.

Dual-licensed under MIT or Apache 2.0.

> Note: the `main` branch can contain unreleased changes. To view the README information for the latest stable release,
> visit [crates.io]https://crates.io/crates/lintspec or select the latest git tag from the branch/tag dropdown.

## Installation

#### Via `cargo`

```bash
cargo install lintspec
```

#### Via [`cargo-binstall`]https://github.com/cargo-bins/cargo-binstall

```bash
cargo binstall lintspec
```

#### Via `nix`

```bash
nix-env -iA nixpkgs.lintspec
# or
nix-shell -p lintspec
# or
nix run nixpkgs#lintspec
```

#### Pre-built binaries and install script

Head over to the [releases page](https://github.com/beeb/lintspec/releases)!

### Experimental `solar` backend

An experimental (and very fast) parsing backend using [Solar](https://github.com/paradigmxyz/solar) can be tested
by installing with the `solar` feature flag enabled. This is only possible via `cargo install` at the moment.

```bash
cargo install lintspec --no-default-features -F cli,solar
```

With this backend, the parsing step is roughly 30x faster than with the default
[`slang`](https://github.com/NomicFoundation/slang) backend. In practice, overall gains of 4-5x can be expected on the
total execution time.
**Note that Solar only supports Solidity >=0.8.0.**

## Usage

```text
Usage: lintspec [OPTIONS] [PATH]... [COMMAND]

Commands:
  init         Create a `.lintspec.toml` config file with default values
  completions  Generate shell completion scripts
  help         Print this message or the help of the given subcommand(s)

Arguments:
  [PATH]...  One or more paths to files and folders to analyze

Options:
  -e, --exclude <EXCLUDE>        Path to a file or folder to exclude (can be used more than once)
      --config <CONFIG>          Optional path to a TOML config file
  -o, --out <OUT>                Write output to a file instead of stderr
      --inheritdoc               Enforce that all public and external items have `@inheritdoc`
      --inheritdoc-override      Enforce that `override` internal functions and modifiers have `@inheritdoc`
      --notice-or-dev            Do not distinguish between `@notice` and `@dev` when considering "required" validation rules
      --skip-version-detection   Skip the detection of the Solidity version from pragma statements
      --notice-ignored <TYPE>    Ignore `@notice` for these items (can be used more than once)
      --notice-required <TYPE>   Enforce `@notice` for these items (can be used more than once)
      --notice-forbidden <TYPE>  Forbid `@notice` for these items (can be used more than once)
      --dev-ignored <TYPE>       Ignore `@dev` for these items (can be used more than once)
      --dev-required <TYPE>      Enforce `@dev` for these items (can be used more than once)
      --dev-forbidden <TYPE>     Forbid `@dev` for these items (can be used more than once)
      --param-ignored <TYPE>     Ignore `@param` for these items (can be used more than once)
      --param-required <TYPE>    Enforce `@param` for these items (can be used more than once)
      --param-forbidden <TYPE>   Forbid `@param` for these items (can be used more than once)
      --return-ignored <TYPE>    Ignore `@return` for these items (can be used more than once)
      --return-required <TYPE>   Enforce `@return` for these items (can be used more than once)
      --return-forbidden <TYPE>  Forbid `@return` for these items (can be used more than once)
      --json                     Output diagnostics in JSON format
      --compact                  Compact output
      --sort                     Sort the results by file path
  -h, --help                     Print help (see more with '--help')
  -V, --version                  Print version
```

## Configuration

### Config File

Create a default configuration with the following command:

```bash
lintspec init
```

This will create a `.lintspec.toml` file with the default configuration in the current directory.

### Environment Variables

Environment variables (in capitals, with the `LS_` prefix) can also be used and take precedence over the
configuration file. They use the same names as in the TOML config file and use the `_` character as delimiter for
nested items.
An additional `LS_CONFIG_PATH` variable is available to set an optional path to the TOML file (the default is `./.lintspec.toml`).

Examples:

- `LS_CONFIG_PATH=.config/lintspec.toml`
- `LS_LINTSPEC_PATHS=[src,test]`
- `LS_LINTSPEC_INHERITDOC=false`
- `LS_LINTSPEC_NOTICE_OR_DEV=true`: if the setting name contains `_`, it is not considered a delimiter
- `LS_OUTPUT_JSON=true`
- `LS_CONSTRUCTOR_NOTICE=required`

### CLI Arguments

Finally, the tool can be customized with command-line arguments, which take precedence over the other two methods.
To see the CLI usage information, run:

```bash
lintspec help
```

## Usage in GitHub Actions

You can check your code in CI with the lintspec GitHub Action. Any `.lintspec.toml` or `.nsignore` file in the
repository's root will be used to configure the execution.

The action generates
[annotations](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-a-warning-message)
that are displayed in the source files when viewed (e.g. in a PR's "Files" tab).

### Options

The following options are available for the action (all are optional if a config file is present):

| Input | Default Value | Description | Example |
|---|---|---|---|
| `working-directory` | `"./"` | Working directory path | `"./src"` |
| `paths` | `"[]"` | Paths to scan, relative to the working directory, in square brackets and separated by commas. Required unless a `.lintspec.toml` file is present in the working directory. | `"[path/to/file.sol,test/test.sol]"` |
| `exclude` | `"[]"` | Paths to exclude, relative to the working directory, in square brackets and separated by commas | `"[path/to/exclude,other/path.sol]"` |
| `extra-args` | | Extra arguments passed to the `lintspec` command | `"--inheritdoc=false"` |
| `version` | `"latest"` | Version of lintspec to use. For enhanced security, you can pin this to a fixed version | `"0.9.0"` |
| `fail-on-problem` | `"true"` | Whether the action should fail when `NatSpec` problems have been found. Disabling this only creates annotations for found problems, but succeeds | `"false"` |

### Example Workflow

```yaml
name: Lintspec

on:
  pull_request:

jobs:
  lintspec:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: beeb/lintspec@v0.9.0
        # all the lines below are optional
        with:
          working-directory: "./"
          paths: "[]"
          exclude: "[]"
          extra-args: ""
          version: "latest"
          fail-on-problem: "true"
```

## Usage as a Library

`lintspec` can be used as a library, in which case the Solidity parser and CLI-specific dependencies are optional.
For example, consumers could declare the following in their `Cargo.toml`:

```toml
[dependencies]
lintspec = { version = "0.9.0", default-features = false }
```

### Feature flags

All feature flags are optional when used as a library. To compile the binary, at least the `cli` flag and one of the
parser flags must be enabled.

- `cli`: enables compilation as a binary and provides the required dependencies
- `slang`: enables the `slang_solidity` parser backend
- `solar`: enables the `solar` parser backend

## Credits

This tool walks in the footsteps of [natspec-smells](https://github.com/defi-wonderland/natspec-smells), thanks to
them for inspiring this project!

## Comparison with natspec-smells

### Benchmark

On an AMD Ryzen 9 7950X processor with 64GB of RAM, linting the
[Uniswap/v4-core](https://github.com/Uniswap/v4-core) `src` folder on WSL2 (Ubuntu), lintspec v0.6 is about 300x
faster, or 0.33% of the execution time:

```text
Benchmark 1: npx @defi-wonderland/natspec-smells --include 'src/**/*.sol' --enforceInheritdoc --constructorNatspec
  Time (mean ± σ):     14.493 s ±  0.492 s    [User: 13.851 s, System: 1.046 s]
  Range (min … max):   14.129 s … 15.826 s    10 runs

Benchmark 2: lintspec src --compact --param-required struct
  Time (mean ± σ):      44.9 ms ±   1.6 ms    [User: 312.8 ms, System: 51.2 ms]
  Range (min … max):    41.9 ms …  48.9 ms    67 runs

Summary
  lintspec src --compact --param-required struct ran
  322.47 ± 16.01 times faster than npx @defi-wonderland/natspec-smells --include 'src/**/*.sol' --enforceInheritdoc --constructorNatspec
```

Using the experimental [Solar](https://github.com/paradigmxyz/solar) backend improves that by a further factor of 4-5x:

```text
Benchmark 1: lintspec src --compact --skip-version-detection
  Time (mean ± σ):      58.4 ms ±   4.3 ms    [User: 484.7 ms, System: 16.6 ms]
  Range (min … max):    50.1 ms …  66.9 ms    52 runs

Benchmark 2: lintspec-solar src --compact
  Time (mean ± σ):      12.2 ms ±   1.3 ms    [User: 21.5 ms, System: 8.5 ms]
  Range (min … max):     9.9 ms …  16.5 ms    183 runs

Summary
  lintspec-solar src --compact ran
    4.77 ± 0.62 times faster than lintspec src --compact --skip-version-detection
```

### Features

| Feature                         | `lintspec` | `natspec-smells` |
|---------------------------------|------------|------------------|
| Identify missing NatSpec        |||
| Identify duplicate NatSpec      |||
| Include files/folders           |||
| Exclude files/folders           |||
| Enforce usage of `@inheritdoc`  |||
| Enforce NatSpec on constructors |||
| Configure via config file       |||
| Configure via env variables     |||
| Respects gitignore files        |||
| Granular validation rules       |||
| Pretty output with code excerpt |||
| JSON output                     |||
| Output to file                  |||
| Multithreaded                   |||
| Built-in CI action              |||
| No pre-requisites (node/npm)    |||