🔎 lintspec
Lintspec is a command-line utility (linter) that checks the completeness and validity of NatSpec 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 or select the latest git tag from the branch/tag dropdown.
Installation
Via cargo
Via cargo-binstall
Via nix
# or
# or
Pre-built binaries and install script
Head over to the releases page!
Experimental solar
backend
An experimental (and very fast) parsing backend using Solar can be tested
by installing with the solar
feature flag enabled. This is only possible via cargo install
at the moment.
With this backend, the parsing step is roughly 15x faster than with the default
slang
backend. In practice, overall gains of 2-3x can be expected on the
total execution time.
Note that Solar only supports Solidity >=0.8.0.
Usage
Usage: lintspec [OPTIONS] [PATH]... [COMMAND]
Commands:
init Create a `.lintspec.toml` config file with default values
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`
--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:
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 delimiterLS_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:
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 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.4.1" |
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
name: Lintspec
on:
pull_request:
jobs:
lintspec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: beeb/lintspec@v0.7.0
# all the lines below are optional
with:
working-directory: "./"
paths: "[]"
exclude: "[]"
extra-args: ""
version: "latest"
fail-on-problem: "true"
Credits
This tool walks in the footsteps of 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 src
folder on WSL2 (Ubuntu), lintspec v0.6 is about 300x
faster, or 0.33% of the execution time:
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 backend improves that by a further factor of 2-3x:
Benchmark 1: lintspec src --compact --skip-version-detection
Time (mean ± σ): 44.8 ms ± 1.9 ms [User: 308.8 ms, System: 49.8 ms]
Range (min … max): 41.3 ms … 49.9 ms 69 runs
Benchmark 2: lintspec-solar src --compact
Time (mean ± σ): 19.7 ms ± 0.7 ms [User: 15.0 ms, System: 30.7 ms]
Range (min … max): 18.5 ms … 21.9 ms 143 runs
Summary
lintspec-solar src --compact ran
2.27 ± 0.13 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) | ✅ | ❌ |