2023-10-03 18:27:00 +09:00
[![Build Status ](https://github.com/mgechev/revive/actions/workflows/test.yaml/badge.svg )](https://github.com/mgechev/revive/actions/workflows/test.yaml)
2018-05-26 16:39:22 -07:00
2017-08-27 20:57:46 -07:00
# revive
2018-06-01 11:28:50 -07:00
Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. ** `Revive` provides a framework for development of custom rules, and lets you define a strict preset for enhancing your development & code review processes**.
2017-08-27 21:05:02 -07:00
2017-08-27 21:00:20 -07:00
< p align = "center" >
2018-05-30 13:44:18 -07:00
< img src = "./assets/logo.png" alt = "" width = "300" >
< br >
Logo by < a href = "https://github.com/hawkgs" > Georgi Serev< / a >
2017-08-27 21:00:20 -07:00
< / p >
2017-08-27 20:59:53 -07:00
2018-02-04 13:42:05 -08:00
Here's how `revive` is different from `golint` :
2018-12-04 19:42:55 +03:00
- Allows to enable or disable rules using a configuration file.
- Allows to configure the linting rules with a TOML file.
2018-06-08 10:28:17 -07:00
- 2x faster running the same rules as golint.
- Provides functionality for disabling a specific rule or the entire linter for a file or a range of lines.
- `golint` allows this only for generated files.
- Optional type checking. Most rules in golint do not require type checking. If you disable them in the config file, revive will run over 6x faster than golint.
- Provides multiple formatters which let us customize the output.
2018-12-04 19:42:55 +03:00
- Allows to customize the return code for the entire linter or based on the failure of only some rules.
2018-06-08 10:28:17 -07:00
- _Everyone can extend it easily with custom rules or formatters._
- `Revive` provides more rules compared to `golint` .
2018-02-04 13:42:05 -08:00
2018-11-25 17:56:04 -08:00
## Who uses Revive
- [`tidb` ](https://github.com/pingcap/tidb ) - TiDB is a distributed HTAP database compatible with the MySQL protocol
2019-04-19 17:53:01 -07:00
- [`grafana` ](https://github.com/grafana/grafana ) - The tool for beautiful monitoring and metric analytics & dashboards for Graphite, InfluxDB & Prometheus & More
- [`etcd` ](https://github.com/etcd-io/etcd ) - Distributed reliable key-value store for the most critical data of a distributed system
2021-08-18 11:03:47 -07:00
- [`cadence` ](https://github.com/uber/cadence ) - Cadence is a distributed, scalable, durable, and highly available orchestration engine by Uber to execute asynchronous long-running business logic in a scalable and resilient way
2018-11-25 17:56:04 -08:00
- [`ferret` ](https://github.com/MontFerret/ferret ) - Declarative web scraping
- [`gopass` ](https://github.com/gopasspw/gopass ) - The slightly more awesome standard unix password manager for teams
2018-12-04 17:45:11 +01:00
- [`gitea` ](https://github.com/go-gitea/gitea ) - Git with a cup of tea, painless self-hosted git service
2018-12-10 22:05:14 +08:00
- [`excelize` ](https://github.com/360EntSecGroup-Skylar/excelize ) - Go library for reading and writing Microsoft Excel™ (XLSX) files
- [`aurora` ](https://github.com/xuri/aurora ) - aurora is a web-based Beanstalk queue server console written in Go
2019-04-19 17:56:36 -07:00
- [`soar` ](https://github.com/XiaoMi/soar ) - SQL Optimizer And Rewriter
2021-03-30 13:33:56 -07:00
- [`pyroscope` ](https://github.com/pyroscope-io/pyroscope ) - Continuous profiling platform
2021-10-08 15:33:22 +08:00
- [`gorush` ](https://github.com/appleboy/gorush ) - A push notification server written in Go (Golang).
2020-08-21 23:47:15 +03:00
- [`dry` ](https://github.com/moncho/dry ) - dry - A Docker manager for the terminal.
2019-07-09 21:51:26 -07:00
- [`go-echarts` ](https://github.com/chenjiandongx/go-echarts ) - The adorable charts library for Golang
- [`reviewdog` ](https://github.com/reviewdog/reviewdog ) - Automated code review tool integrated with any code analysis tools regardless of programming language
2020-08-21 23:47:15 +03:00
- [`rudder-server` ](https://github.com/rudderlabs/rudder-server ) - Privacy and Security focused Segment-alternative, in Golang and React.
- [`sklearn` ](https://github.com/pa-m/sklearn ) - A partial port of scikit-learn written in Go.
- [`protoc-gen-doc` ](https://github.com/pseudomuto/protoc-gen-doc ) - Documentation generator plugin for Google Protocol Buffers.
- [`llvm` ](https://github.com/llir/llvm ) - Library for interacting with LLVM IR in pure Go.
- [`jenkins-library` ](https://github.com/SAP/jenkins-library ) - Jenkins shared library for Continuous Delivery pipelines by SAP.
- [`pd` ](https://github.com/tikv/pd ) - Placement driver for TiKV.
- [`shellhub` ](https://github.com/shellhub-io/shellhub ) - ShellHub enables teams to easily access any Linux device behind firewall and NAT.
2019-07-09 21:51:26 -07:00
- [`lorawan-stack` ](https://github.com/TheThingsNetwork/lorawan-stack ) - The Things Network Stack for LoRaWAN V3
2020-08-21 23:47:15 +03:00
- [`gin-jwt` ](https://github.com/appleboy/gin-jwt ) - This is a JWT middleware for Gin framework.
2019-07-09 21:51:26 -07:00
- [`gofight` ](https://github.com/appleboy/gofight ) - Testing API Handler written in Golang.
2020-08-21 23:47:15 +03:00
- [`Beaver` ](https://github.com/Clivern/Beaver ) - A Real Time Messaging Server.
2019-07-09 21:51:26 -07:00
- [`ggz` ](https://github.com/go-ggz/ggz ) - An URL shortener service written in Golang
2019-08-05 18:50:10 +02:00
- [`Codeac.io` ](https://www.codeac.io?ref=revive ) - Automated code review service integrates with GitHub, Bitbucket and GitLab (even self-hosted) and helps you fight technical debt.
2022-07-12 16:15:02 +08:00
- [`DevLake` ](https://github.com/apache/incubator-devlake ) - Apache DevLake is an open-source dev data platform to ingest, analyze, and visualize the fragmented data from DevOps tools,which can distill insights to improve engineering productivity.
2023-06-21 23:56:53 -07:00
- [`checker` ](https://github.com/cinar/checker ) - Checker helps validating user input through rules defined in struct tags or directly through functions.
2023-07-05 14:12:42 +08:00
- [`milvus` ](https://github.com/milvus-io/milvus ) - A cloud-native vector database, storage for next generation AI applications.
2024-11-04 04:20:19 -08:00
- [`indicator` ](https://github.com/cinar/indicator ) - Indicator provides various technical analysis indicators, strategies, and a backtesting framework.
2018-11-25 17:56:04 -08:00
*Open a PR to add your project*.
2018-05-30 13:42:28 -07:00
< p align = "center" >
2018-05-30 13:44:18 -07:00
< img src = "./assets/demo.svg" alt = "" width = "700" >
2018-05-30 13:42:28 -07:00
< / p >
2018-06-08 10:28:17 -07:00
<!-- TOC -->
- [revive ](#revive )
2024-10-25 15:34:38 +03:00
- [Who uses Revive ](#who-uses-revive )
2021-08-17 18:02:22 +02:00
- [Installation ](#installation )
2018-07-07 15:15:12 -07:00
- [Usage ](#usage )
2022-10-12 08:32:14 +04:00
- [Docker ](#docker )
2021-05-23 22:31:35 +02:00
- [Bazel ](#bazel )
2018-07-07 15:15:12 -07:00
- [Text Editors ](#text-editors )
2022-10-12 08:32:14 +04:00
- [GitHub Actions ](#github-actions )
2019-08-05 18:50:10 +02:00
- [Continuous Integration ](#continuous-integration )
2024-10-25 15:34:38 +03:00
- [Linter aggregators ](#linter-aggregators )
2021-05-23 22:31:35 +02:00
- [golangci-lint ](#golangci-lint )
2018-07-07 15:15:12 -07:00
- [Command Line Flags ](#command-line-flags )
- [Sample Invocations ](#sample-invocations )
2022-10-06 17:05:23 +08:00
- [Comment Directives ](#comment-directives )
2018-07-07 15:15:12 -07:00
- [Configuration ](#configuration )
- [Default Configuration ](#default-configuration )
2018-07-23 16:44:51 -07:00
- [Custom Configuration ](#custom-configuration )
2018-07-07 15:15:12 -07:00
- [Recommended Configuration ](#recommended-configuration )
2024-10-25 15:34:38 +03:00
- [Rule-level file excludes ](#rule-level-file-excludes )
2018-07-07 15:15:12 -07:00
- [Available Rules ](#available-rules )
2018-10-03 16:01:41 +08:00
- [Configurable rules ](#configurable-rules )
- [`var-naming` ](#var-naming )
2018-07-07 15:15:12 -07:00
- [Available Formatters ](#available-formatters )
- [Friendly ](#friendly )
- [Stylish ](#stylish )
- [Default ](#default )
2018-10-31 15:32:23 +01:00
- [Plain ](#plain )
- [Unix ](#unix )
2024-11-22 09:21:43 +02:00
- [JSON ](#json )
- [NDJSON ](#ndjson )
- [Checkstyle ](#checkstyle )
2021-04-05 20:54:33 +02:00
- [SARIF ](#sarif )
2018-07-07 15:15:12 -07:00
- [Extensibility ](#extensibility )
2024-10-25 15:34:38 +03:00
- [Writing a Custom Rule ](#writing-a-custom-rule )
2018-07-07 15:15:12 -07:00
- [Example ](#example )
2024-10-25 15:34:38 +03:00
- [Using `revive` as a library ](#using-revive-as-a-library )
2018-07-07 15:15:12 -07:00
- [Custom Formatter ](#custom-formatter )
- [Speed Comparison ](#speed-comparison )
- [golint ](#golint )
2024-10-25 15:34:38 +03:00
- [revive's speed ](#revives-speed )
2020-05-14 23:08:30 +02:00
- [Overriding colorization detection ](#overriding-colorization-detection )
2018-07-07 15:15:12 -07:00
- [Contributors ](#contributors )
- [License ](#license )
2018-06-08 10:28:17 -07:00
<!-- /TOC -->
2021-08-17 18:02:22 +02:00
## Installation
```bash
go install github.com/mgechev/revive@latest
```
or get a released executable from the [Releases ](https://github.com/mgechev/revive/releases ) page.
You can install the main branch (including the last commit) with:
```bash
go install github.com/mgechev/revive@master
```
2018-02-04 12:19:24 -08:00
## Usage
2018-05-26 15:17:28 -07:00
Since the default behavior of `revive` is compatible with `golint` , without providing any additional flags, the only difference you'd notice is faster execution.
2018-02-04 12:19:24 -08:00
2020-08-03 17:29:08 +03:00
`revive` supports a `-config` flag whose value should correspond to a TOML file describing which rules to use for `revive` 's linting. If not provided, `revive` will try to use a global config file (assumed to be located at `$HOME/revive.toml` ). Otherwise, if no configuration TOML file is found then `revive` uses a built-in set of default linting rules.
2019-09-17 08:38:25 -07:00
2021-10-15 08:36:14 +02:00
### Docker
2024-10-25 15:34:38 +03:00
2024-07-11 11:26:42 +03:30
A volume must be mounted to share the current repository with the container.
2021-10-15 08:36:14 +02:00
Please refer to the [bind mounts Docker documentation ](https://docs.docker.com/storage/bind-mounts/ )
```bash
2024-07-11 11:26:42 +03:30
docker run -v "$(pwd)":/var/< repository > ghcr.io/mgechev/revive:v1.3.7 -config /var/< repository > /revive.toml -formatter stylish ./var/kidle/...
2021-10-15 08:36:14 +02:00
```
2023-10-27 07:26:27 +02:00
- `-v` is for the volume
2024-07-11 11:26:42 +03:30
- `ghcr.io/mgechev/revive:v1.3.7 ` is the image name and its version corresponds to `revive` command
2021-10-15 08:36:14 +02:00
- The provided flags are the same as the binary usage.
2019-07-09 21:51:26 -07:00
### Bazel
2024-07-11 11:26:42 +03:30
If you want to use revive with Bazel, look at the [rules ](https://github.com/atlassian/bazel-tools/tree/master/gorevive ) that Atlassian maintains.
2019-07-09 21:51:26 -07:00
2018-05-30 18:34:35 -07:00
### Text Editors
2018-06-08 10:28:17 -07:00
- Support for VSCode in [vscode-go ](https://github.com/Microsoft/vscode-go/pull/1699 ).
2021-03-30 13:33:56 -07:00
- Support for GoLand via [File Watchers ](https://dev.to/s0xzwasd/configure-revive-go-linter-in-goland-2ggl ).
2018-07-31 12:20:58 -07:00
- Support for Atom via [linter-revive ](https://github.com/morphy2k/linter-revive ).
2020-07-07 19:13:13 +08:00
- Support for vim via [dense-analysis/ale ](https://github.com/dense-analysis/ale ).
2018-07-13 15:02:51 -07:00
2022-08-20 01:58:47 -03:00
```vim
let g:ale_linters = {
\ 'go': ['revive'],
\}
```
- Support for Neovim via [null-ls.nvim ](https://github.com/jose-elias-alvarez/null-ls.nvim ).
```lua
require("null-ls").setup({
sources = {
require("null-ls").builtins.diagnostics.revive
},
})
```
2018-07-13 15:02:51 -07:00
2019-08-31 23:29:52 +02:00
### GitHub Actions
- [Revive Action ](https://github.com/marketplace/actions/revive-action ) with annotation support
2019-08-05 18:50:10 +02:00
### Continuous Integration
[Codeac.io ](https://www.codeac.io?ref=revive ) - Automated code review service integrates with GitHub, Bitbucket and GitLab (even self-hosted) and helps you fight technical debt. Check your [pull-requests ](https://www.codeac.io/documentation/pull-requests.html?ref=revive ) with [revive ](https://www.codeac.io/documentation/revive-configuration.html?ref=revive ) automatically. (free for open-source projects)
2021-05-23 22:31:35 +02:00
### Linter aggregators
#### golangci-lint
2024-10-25 15:34:38 +03:00
2021-05-23 22:31:35 +02:00
To enable `revive` in `golangci-lint` you need to add `revive` to the list of enabled linters:
```yaml
# golangci-lint configuration file
linters:
enable:
- revive
```
Then `revive` can be configured by adding an entry to the `linters-settings` section of the configuration, for example:
```yaml
# golangci-lint configuration file
linters-settings:
revive:
ignore-generated-header: true
severity: warning
rules:
- name: atomic
- name: line-length-limit
severity: error
arguments: [80]
- name: unhandled-error
arguments : ["fmt.Printf", "myFunction"]
```
2021-06-02 10:41:53 -07:00
The above configuration enables three rules of `revive` : _atomic_ , _line-length-limit_ and _unhandled-error_ and pass some arguments to the last two.
2021-05-23 22:31:35 +02:00
The [Configuration ](#configuration ) section of this document provides details on how to configure `revive` . Note that while `revive` configuration is in TOML, that of `golangci-lint` is in YAML.
Please notice that if no particular configuration is provided, `revive` will behave as `go-lint` does, i.e. all `go-lint` rules are enabled (the [Available Rules table ](#available-rules ) details what are the `go-lint` rules). When a configuration is provided, only rules in the configuration are enabled.
2018-02-04 12:19:24 -08:00
### Command Line Flags
2022-02-08 02:36:03 +01:00
`revive` accepts the following command line parameters:
2018-02-04 12:19:24 -08:00
2024-07-11 11:26:42 +03:30
- `-config [PATH]` - path to the config file in TOML format, defaults to `$HOME/revive.toml` if present.
2024-10-28 09:15:06 -03:00
- `-exclude [PATTERN]` - pattern for files/directories/packages to be excluded for linting. You can specify the files you want to exclude for linting either as package name (i.e. `github.com/mgechev/revive` ), list them as individual files (i.e. `file.go` ), directories (i.e. `./foo/...` ), or any combination of the three. If no exclusion patterns are specified, `vendor/...` will be excluded by default.
2018-06-08 10:28:17 -07:00
- `-formatter [NAME]` - formatter to be used for the output. The currently available formatters are:
2018-07-23 16:44:51 -07:00
2018-06-08 10:28:17 -07:00
- `default` - will output the failures the same way that `golint` does.
- `json` - outputs the failures in JSON format.
2024-07-11 11:26:42 +03:30
- `ndjson` - outputs the failures as a stream in newline delimited JSON (NDJSON) format.
- `friendly` - outputs the failures when found. Shows the summary of all the failures.
2018-06-08 10:28:17 -07:00
- `stylish` - formats the failures in a table. Keep in mind that it doesn't stream the output so it might be perceived as slower compared to others.
2018-07-15 21:45:15 +02:00
- `checkstyle` - outputs the failures in XML format compatible with that of Java's [Checkstyle ](https://checkstyle.org/ ).
2022-02-08 02:36:03 +01:00
- `-max_open_files` - maximum number of open files at the same time. Defaults to unlimited.
- `-set_exit_status` - set exit status to 1 if any issues are found, overwrites `errorCode` and `warningCode` in config.
- `-version` - get revive version.
2018-07-23 16:44:51 -07:00
2018-05-26 15:17:28 -07:00
### Sample Invocations
```shell
revive -config revive.toml -exclude file1.go -exclude file2.go -formatter friendly github.com/mgechev/revive package/...
```
2018-06-08 10:28:17 -07:00
- The command above will use the configuration from `revive.toml`
- `revive` will ignore `file1.go` and `file2.go`
- The output will be formatted with the `friendly` formatter
- The linter will analyze `github.com/mgechev/revive` and the files in `package`
2018-05-26 15:17:28 -07:00
2019-08-02 17:21:33 +02:00
### Comment Directives
2018-06-01 10:54:30 -07:00
2024-07-11 11:26:42 +03:30
Using comments, you can disable the linter for the entire file or only a range of lines:
2018-06-01 10:54:30 -07:00
```go
//revive:disable
func Public() {}
//revive:enable
```
The snippet above, will disable `revive` between the `revive:disable` and `revive:enable` comments. If you skip `revive:enable` , the linter will be disabled for the rest of the file.
2018-08-14 22:22:52 +02:00
With `revive:disable-next-line` and `revive:disable-line` you can disable `revive` on a particular code line.
2018-06-01 10:54:30 -07:00
You can do the same on a rule level. In case you want to disable only a particular rule, you can use:
```go
//revive:disable:unexported-return
func Public() private {
return private
}
//revive:enable:unexported-return
```
2024-07-11 11:26:42 +03:30
This way, `revive` will not warn you that you're returning an object of an unexported type, from an exported function.
2018-06-01 10:54:30 -07:00
2019-08-02 17:21:33 +02:00
You can document why you disable the linter by adding a trailing text in the directive, for example
```go
//revive:disable Until the code is stable
```
2024-10-25 15:34:38 +03:00
2019-08-02 17:21:33 +02:00
```go
2020-08-03 17:29:08 +03:00
//revive:disable:cyclomatic High complexity score but easy to understand
2019-08-02 17:21:33 +02:00
```
You can also configure `revive` to enforce documenting linter disabling directives by adding
```toml
[directive.specify-disable-reason]
```
in the configuration. You can set the severity (defaults to _warning_ ) of the violation of this directive
```toml
[directive.specify-disable-reason]
severity = "error"
```
2018-02-04 12:19:24 -08:00
### Configuration
2024-07-11 11:26:42 +03:30
`revive` can be configured with a TOML file. Here's a sample configuration with an explanation of the individual properties:
2018-05-26 15:17:28 -07:00
```toml
2018-06-01 10:30:40 -07:00
# When set to false, ignores files with "GENERATED" header, similar to golint
2018-05-26 15:17:28 -07:00
ignoreGeneratedHeader = true
# Sets the default severity to "warning"
severity = "warning"
# Sets the default failure confidence. This means that linting errors
# with less than 0.8 confidence will be ignored.
confidence = 0.8
2024-07-11 11:26:42 +03:30
# Sets the error code for failures with the "error" severity
2018-05-26 15:17:28 -07:00
errorCode = 0
# Sets the error code for failures with severity "warning"
warningCode = 0
# Configuration of the `cyclomatic` rule. Here we specify that
# the rule should fail if it detects code with higher complexity than 10.
[rule.cyclomatic]
arguments = [10]
# Sets the severity of the `package-comments` rule to "error".
[rule.package-comments]
severity = "error"
```
2018-02-04 12:19:24 -08:00
2021-05-21 09:53:10 +02:00
By default `revive` will enable only the linting rules that are named in the configuration file.
For example, the previous configuration file makes `revive` to enable only _cyclomatic_ and _package-comments_ linting rules.
To enable all available rules you need to add:
```toml
enableAllRules = true
```
2024-07-11 11:26:42 +03:30
This will enable all available rules no matter what rules are named in the configuration file.
2021-05-21 09:53:10 +02:00
To disable a rule, you simply mark it as disabled in the configuration.
For example:
```toml
[rule.line-length-limit]
Disabled = true
```
2024-10-25 15:34:38 +03:00
2021-05-21 09:53:10 +02:00
When enabling all rules you still need/can provide specific configurations for rules.
2024-07-11 11:26:42 +03:30
The following file is an example configuration where all rules are enabled, except for those that are explicitly disabled, and some rules are configured with particular arguments:
2021-05-21 09:53:10 +02:00
```toml
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0
# Enable all available rules
enableAllRules = true
# Disabled rules
[rule.blank-imports]
Disabled = true
[rule.file-header]
Disabled = true
[rule.max-public-structs]
Disabled = true
[rule.line-length-limit]
Disabled = true
[rule.function-length]
Disabled = true
2022-08-08 13:21:09 +02:00
[rule.banned-characters]
Disabled = true
2021-05-21 09:53:10 +02:00
2021-07-01 00:25:34 +08:00
# Rule tuning
2021-05-21 09:53:10 +02:00
[rule.argument-limit]
Arguments = [5]
2021-06-02 10:41:53 -07:00
[rule.cyclomatic]
2021-05-21 09:53:10 +02:00
Arguments = [10]
2021-06-02 10:41:53 -07:00
[rule.cognitive-complexity]
2021-05-21 09:53:10 +02:00
Arguments = [7]
2021-06-02 10:41:53 -07:00
[rule.function-result-limit]
2021-05-21 09:53:10 +02:00
Arguments = [3]
2022-07-06 03:51:50 +08:00
[rule.error-strings]
Arguments = ["mypackage.Error"]
2021-05-21 09:53:10 +02:00
```
2018-02-04 13:42:05 -08:00
### Default Configuration
2018-02-18 22:19:37 -08:00
The default configuration of `revive` can be found at `defaults.toml` . This will enable all rules available in `golint` and use their default configuration (i.e. the way they are hardcoded in `golint` ).
2018-02-04 13:42:05 -08:00
```shell
revive -config defaults.toml github.com/mgechev/revive
```
2018-02-18 22:19:37 -08:00
This will use the configuration file `defaults.toml` , the `default` formatter, and will run linting over the `github.com/mgechev/revive` package.
2018-02-04 13:42:05 -08:00
2018-07-23 16:44:51 -07:00
### Custom Configuration
2018-02-04 13:42:05 -08:00
```shell
2018-05-26 15:17:28 -07:00
revive -config config.toml -formatter friendly github.com/mgechev/revive
2018-02-04 13:42:05 -08:00
```
2018-05-26 15:17:28 -07:00
This will use `config.toml` , the `friendly` formatter, and will run linting over the `github.com/mgechev/revive` package.
2018-02-04 13:42:05 -08:00
2018-07-23 16:44:51 -07:00
### Recommended Configuration
The following snippet contains the recommended `revive` configuration that you can use in your project:
```toml
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]
[rule.empty-block]
[rule.superfluous-else]
[rule.unused-parameter]
[rule.unreachable-code]
2018-09-13 19:21:28 -07:00
[rule.redefines-builtin-id]
2018-07-23 16:44:51 -07:00
```
2023-08-12 11:21:11 +05:00
### Rule-level file excludes
You also can setup custom excludes for each rule.
2024-07-11 11:26:42 +03:30
It's an alternative for the global `-exclude` program arg.
2023-08-12 11:21:11 +05:00
```toml
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 0
warningCode = 0
[rule.blank-imports]
Exclude=["**/*.pb.go"]
[rule.context-as-argument]
Exclude=["src/somepkg/*.go", "TEST"]
```
2024-07-11 11:26:42 +03:30
You can use the following exclude patterns
2023-08-12 11:21:11 +05:00
1. full paths to files `src/pkg/mypkg/some.go`
2. globs `src/**/*.pb.go`
3. regexes (should have prefix ~) `~\.(pb|auto|generated)\.go$`
4. well-known `TEST` (same as `**/*_test.go` )
5. special cases:
2024-07-11 11:26:42 +03:30
a. `*` and `~` patterns exclude all files (same effect as disabling the rule)
2023-08-12 11:21:11 +05:00
b. `""` (empty) pattern excludes nothing
2024-07-11 11:26:42 +03:30
> NOTE: do not mess with `exclude` that can be used at the top level of TOML file, that means "exclude package patterns", not "exclude file patterns"
2023-08-12 11:21:11 +05:00
2018-02-18 22:26:59 -08:00
## Available Rules
2018-06-13 22:35:38 +03:00
List of all available rules. The rules ported from `golint` are left unchanged and indicated in the `golint` column.
2018-05-31 21:14:00 -07:00
| Name | Config | Description | `golint` | Typed |
| --------------------- | :----: | :--------------------------------------------------------------- | :------: | :---: |
2018-10-26 05:15:13 +02:00
| [`context-keys-type` ](./RULES_DESCRIPTIONS.md#context-key-types ) | n/a | Disallows the usage of basic types in `context.WithValue` . | yes | yes |
2021-10-01 15:25:53 +03:30
| [`time-equal` ](./RULES_DESCRIPTIONS.md#time-equal ) | n/a | Suggests to use `time.Time.Equal` instead of `==` and `!=` for equality check time. | no | yes |
2018-10-26 05:15:13 +02:00
| [`time-naming` ](./RULES_DESCRIPTIONS.md#time-naming ) | n/a | Conventions around the naming of time variables. | yes | yes |
2023-09-17 10:58:45 +02:00
| [`unchecked-type-assertions` ](./RULES_DESCRIPTIONS.md#unchecked-type-assertions ) | n/a | Disallows type assertions without checking the result. | no | yes |
2018-10-26 05:15:13 +02:00
| [`var-declaration` ](./RULES_DESCRIPTIONS.md#var-declaration ) | n/a | Reduces redundancies around variable declaration. | yes | yes |
| [`unexported-return` ](./RULES_DESCRIPTIONS.md#unexported-return ) | n/a | Warns when a public return is from unexported type. | yes | yes |
| [`errorf` ](./RULES_DESCRIPTIONS.md#errorf ) | n/a | Should replace `errors.New(fmt.Sprintf())` with `fmt.Errorf()` | yes | yes |
| [`blank-imports` ](./RULES_DESCRIPTIONS.md#blank-imports ) | n/a | Disallows blank imports | yes | no |
| [`context-as-argument` ](./RULES_DESCRIPTIONS.md#context-as-argument ) | n/a | `context.Context` should be the first argument of a function. | yes | no |
| [`dot-imports` ](./RULES_DESCRIPTIONS.md#dot-imports ) | n/a | Forbids `.` imports. | yes | no |
| [`error-return` ](./RULES_DESCRIPTIONS.md#error-return ) | n/a | The error return parameter should be last. | yes | no |
2022-07-06 03:51:50 +08:00
| [`error-strings` ](./RULES_DESCRIPTIONS.md#error-strings ) | []string | Conventions around error strings. | yes | no |
2018-10-26 05:15:13 +02:00
| [`error-naming` ](./RULES_DESCRIPTIONS.md#error-naming ) | n/a | Naming of error variables. | yes | no |
2021-08-26 17:36:24 +02:00
| [`exported` ](./RULES_DESCRIPTIONS.md#exported ) | []string | Naming and commenting conventions on exported symbols. | yes | no |
2021-06-29 22:04:51 +02:00
| [`if-return` ](./RULES_DESCRIPTIONS.md#if-return ) | n/a | Redundant if when returning an error. | no | no |
2018-10-26 05:15:13 +02:00
| [`increment-decrement` ](./RULES_DESCRIPTIONS.md#increment-decrement ) | n/a | Use `i++` and `i--` instead of `i += 1` and `i -= 1` . | yes | no |
2024-02-03 18:36:44 +01:00
| [`var-naming` ](./RULES_DESCRIPTIONS.md#var-naming ) | allowlist & blocklist of initialisms | Naming rules. | yes | no |
2018-10-26 05:15:13 +02:00
| [`package-comments` ](./RULES_DESCRIPTIONS.md#package-comments ) | n/a | Package commenting conventions. | yes | no |
| [`range` ](./RULES_DESCRIPTIONS.md#range ) | n/a | Prevents redundant variables when iterating over a collection. | yes | no |
2024-09-23 12:38:39 +02:00
| [`receiver-naming` ](./RULES_DESCRIPTIONS.md#receiver-naming ) | map (optional) | Conventions around the naming of receivers. | yes | no |
2023-05-23 18:10:09 +10:00
| [`indent-error-flow` ](./RULES_DESCRIPTIONS.md#indent-error-flow ) | []string | Prevents redundant else statements. | yes | no |
2023-05-20 14:44:34 +02:00
| [`argument-limit` ](./RULES_DESCRIPTIONS.md#argument-limit ) | int (defaults to 8) | Specifies the maximum number of arguments a function can receive | no | no |
| [`cyclomatic` ](./RULES_DESCRIPTIONS.md#cyclomatic ) | int (defaults to 10) | Sets restriction for maximum Cyclomatic complexity. | no | no |
| [`max-public-structs` ](./RULES_DESCRIPTIONS.md#max-public-structs ) | int (defaults to 5) | The maximum number of public structs in a file. | no | no |
| [`file-header` ](./RULES_DESCRIPTIONS.md#file-header ) | string (defaults to none)| Header which each file should have. | no | no |
2020-05-11 02:43:56 +02:00
| [`empty-block` ](./RULES_DESCRIPTIONS.md#empty-block ) | n/a | Warns on empty code blocks | no | yes |
2023-05-23 18:10:09 +10:00
| [`superfluous-else` ](./RULES_DESCRIPTIONS.md#superfluous-else ) | []string | Prevents redundant else statements (extends [`indent-error-flow` ](./RULES_DESCRIPTIONS.md#indent-error-flow )) | no | no |
2018-10-26 05:15:13 +02:00
| [`confusing-naming` ](./RULES_DESCRIPTIONS.md#confusing-naming ) | n/a | Warns on methods with names that differ only by capitalization | no | no |
| [`get-return` ](./RULES_DESCRIPTIONS.md#get-return ) | n/a | Warns on getters that do not yield any result | no | no |
| [`modifies-parameter` ](./RULES_DESCRIPTIONS.md#modifies-parameter ) | n/a | Warns on assignments to function parameters | no | no |
| [`confusing-results` ](./RULES_DESCRIPTIONS.md#confusing-results ) | n/a | Suggests to name potentially confusing function results | no | no |
| [`deep-exit` ](./RULES_DESCRIPTIONS.md#deep-exit ) | n/a | Looks for program exits in funcs other than `main()` or `init()` | no | no |
| [`unused-parameter` ](./RULES_DESCRIPTIONS.md#unused-parameter ) | n/a | Suggests to rename or remove unused function parameters | no | no |
| [`unreachable-code` ](./RULES_DESCRIPTIONS.md#unreachable-code ) | n/a | Warns on unreachable code | no | no |
| [`add-constant` ](./RULES_DESCRIPTIONS.md#add-constant ) | map | Suggests using constant for magic numbers and string literals | no | no |
| [`flag-parameter` ](./RULES_DESCRIPTIONS.md#flag-parameter ) | n/a | Warns on boolean parameters that create a control coupling | no | no |
| [`unnecessary-stmt` ](./RULES_DESCRIPTIONS.md#unnecessary-stmt ) | n/a | Suggests removing or simplifying unnecessary statements | no | no |
2023-05-20 14:44:34 +02:00
| [`struct-tag` ](./RULES_DESCRIPTIONS.md#struct-tag ) | []string | Checks common struct tags like `json` , `xml` , `yaml` | no | no |
2018-10-26 05:15:13 +02:00
| [`modifies-value-receiver` ](./RULES_DESCRIPTIONS.md#modifies-value-receiver ) | n/a | Warns on assignments to value-passed method receivers | no | yes |
| [`constant-logical-expr` ](./RULES_DESCRIPTIONS.md#constant-logical-expr ) | n/a | Warns on constant logical expressions | no | no |
| [`bool-literal-in-expr` ](./RULES_DESCRIPTIONS.md#bool-literal-in-expr )| n/a | Suggests removing Boolean literals from logic expressions | no | no |
| [`redefines-builtin-id` ](./RULES_DESCRIPTIONS.md#redefines-builtin-id )| n/a | Warns on redefinitions of builtin identifiers | no | no |
2023-05-20 14:44:34 +02:00
| [`function-result-limit` ](./RULES_DESCRIPTIONS.md#function-result-limit ) | int (defaults to 3)| Specifies the maximum number of results a function can return | no | no |
2024-02-03 18:36:44 +01:00
| [`imports-blocklist` ](./RULES_DESCRIPTIONS.md#imports-blocklist ) | []string | Disallows importing the specified packages | no | no |
2018-10-26 05:15:13 +02:00
| [`range-val-in-closure` ](./RULES_DESCRIPTIONS.md#range-val-in-closure )| n/a | Warns if range value is used in a closure dispatched as goroutine| no | no |
2021-08-26 08:41:58 +02:00
| [`range-val-address` ](./RULES_DESCRIPTIONS.md#range-val-address )| n/a | Warns if address of range value is used dangerously | no | yes |
2018-10-26 05:15:13 +02:00
| [`waitgroup-by-value` ](./RULES_DESCRIPTIONS.md#waitgroup-by-value ) | n/a | Warns on functions taking sync.WaitGroup as a by-value parameter | no | no |
| [`atomic` ](./RULES_DESCRIPTIONS.md#atomic ) | n/a | Check for common mistaken usages of the `sync/atomic` package | no | no |
| [`empty-lines` ](./RULES_DESCRIPTIONS.md#empty-lines ) | n/a | Warns when there are heading or trailing newlines in a block | no | no |
2023-05-20 14:44:34 +02:00
| [`line-length-limit` ](./RULES_DESCRIPTIONS.md#line-length-limit ) | int (defaults to 80) | Specifies the maximum number of characters in a line | no | no |
2018-10-31 15:32:23 +01:00
| [`call-to-gc` ](./RULES_DESCRIPTIONS.md#call-to-gc ) | n/a | Warns on explicit call to the garbage collector | no | no |
2019-06-05 14:00:45 +02:00
| [`duplicated-imports` ](./RULES_DESCRIPTIONS.md#duplicated-imports ) | n/a | Looks for packages that are imported two or more times | no | no |
2019-03-27 19:46:20 +01:00
| [`import-shadowing` ](./RULES_DESCRIPTIONS.md#import-shadowing ) | n/a | Spots identifiers that shadow an import | no | no |
2019-06-05 14:00:45 +02:00
| [`bare-return` ](./RULES_DESCRIPTIONS.md#bare-return ) | n/a | Warns on bare returns | no | no |
2019-04-18 19:35:51 +02:00
| [`unused-receiver` ](./RULES_DESCRIPTIONS.md#unused-receiver ) | n/a | Suggests to rename or remove unused method receivers | no | no |
2022-08-08 13:48:59 +02:00
| [`unhandled-error` ](./RULES_DESCRIPTIONS.md#unhandled-error ) | []string | Warns on unhandled errors returned by function calls | no | yes |
2023-05-20 14:44:34 +02:00
| [`cognitive-complexity` ](./RULES_DESCRIPTIONS.md#cognitive-complexity ) | int (defaults to 7) | Sets restriction for maximum Cognitive complexity. | no | no |
2020-02-18 18:38:01 +01:00
| [`string-of-int` ](./RULES_DESCRIPTIONS.md#string-of-int ) | n/a | Warns on suspicious casts from int to string | no | yes |
2021-04-18 12:35:30 -04:00
| [`string-format` ](./RULES_DESCRIPTIONS.md#string-format ) | map | Warns on specific string literals that fail one or more user-configured regular expressions | no | no |
2023-05-23 18:10:09 +10:00
| [`early-return` ](./RULES_DESCRIPTIONS.md#early-return ) | []string | Spots if-then-else statements where the predicate may be inverted to reduce nesting | no | no |
2020-05-09 17:19:37 +02:00
| [`unconditional-recursion` ](./RULES_DESCRIPTIONS.md#unconditional-recursion ) | n/a | Warns on function calls that will lead to (direct) infinite recursion | no | no |
2020-05-08 22:21:34 +02:00
| [`identical-branches` ](./RULES_DESCRIPTIONS.md#identical-branches ) | n/a | Spots if-then-else statements with identical `then` and `else` branches | no | no |
2020-05-24 20:49:49 +02:00
| [`defer` ](./RULES_DESCRIPTIONS.md#defer ) | map | Warns on some [defer gotchas ](https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-iii-36a1ab3d6ef1 ) | no | no |
2020-07-23 01:17:20 +02:00
| [`unexported-naming` ](./RULES_DESCRIPTIONS.md#unexported-naming ) | n/a | Warns on wrongly named un-exported symbols | no | no |
2023-05-20 14:44:34 +02:00
| [`function-length` ](./RULES_DESCRIPTIONS.md#function-length ) | int, int (defaults to 50 statements, 75 lines) | Warns on functions exceeding the statements or lines max | no | no |
2021-06-15 05:36:41 -04:00
| [`nested-structs` ](./RULES_DESCRIPTIONS.md#nested-structs ) | n/a | Warns on structs within structs | no | no |
2021-08-16 00:30:08 +02:00
| [`useless-break` ](./RULES_DESCRIPTIONS.md#useless-break ) | n/a | Warns on useless `break` statements in case clauses | no | no |
2023-05-20 14:44:34 +02:00
| [`banned-characters` ](./RULES_DESCRIPTIONS.md#banned-characters ) | []string (defaults to []string{}) | Checks banned characters in identifiers | no | no |
2021-10-23 09:29:14 +02:00
| [`optimize-operands-order` ](./RULES_DESCRIPTIONS.md#optimize-operands-order ) | n/a | Checks inefficient conditional expressions | no | no |
2022-03-29 20:25:38 +02:00
| [`use-any` ](./RULES_DESCRIPTIONS.md#use-any ) | n/a | Proposes to replace `interface{}` with its alias `any` | no | no |
2022-04-18 18:45:42 +02:00
| [`datarace` ](./RULES_DESCRIPTIONS.md#datarace ) | n/a | Spots potential dataraces | no | no |
2022-10-29 23:02:42 +05:30
| [`comment-spacings` ](./RULES_DESCRIPTIONS.md#comment-spacings ) | []string | Warns on malformed comments | no | no |
2023-07-31 03:22:40 -03:00
| [`redundant-import-alias` ](./RULES_DESCRIPTIONS.md#redundant-import-alias ) | n/a | Warns on import aliases matching the imported package name | no | no |
2023-10-29 13:19:53 +01:00
| [`import-alias-naming` ](./RULES_DESCRIPTIONS.md#import-alias-naming ) | string or map[string]string (defaults to allow regex pattern ^[a-z][a-z0-9]{0,}$) | Conventions around the naming of import aliases. | no | no |
2023-09-17 11:22:11 +02:00
| [`enforce-map-style` ](./RULES_DESCRIPTIONS.md#enforce-map-style ) | string (defaults to "any") | Enforces consistent usage of `make(map[type]type)` or `map[type]type{}` for map initialization. Does not affect `make(map[type]type, size)` constructions. | no | no |
2023-09-23 09:05:52 +02:00
| [`enforce-slice-style` ](./RULES_DESCRIPTIONS.md#enforce-slice-style ) | string (defaults to "any") | Enforces consistent usage of `make([]type, 0)` or `[]type{}` for slice initialization. Does not affect `make(map[type]type, non_zero_len, or_non_zero_cap)` constructions. | no | no |
2023-12-27 10:30:09 +01:00
| [`enforce-repeated-arg-type-style` ](./RULES_DESCRIPTIONS.md#enforce-repeated-arg-type-style ) | string (defaults to "any") | Enforces consistent style for repeated argument and/or return value types. | no | no |
2024-01-28 12:22:41 +01:00
| [`max-control-nesting` ](./RULES_DESCRIPTIONS.md#max-control-nesting ) | int (defaults to 5) | Sets restriction for maximum nesting of control structures. | no | no |
2024-07-11 11:26:42 +03:30
| [`comments-density` ](./RULES_DESCRIPTIONS.md#comments-density ) | int (defaults to 0) | Enforces a minimum comment / code relation | no | no |
2024-10-26 13:40:24 +03:00
| [`file-length-limit` ](./RULES_DESCRIPTIONS.md#file-length-limit ) | map (optional)| Enforces a maximum number of lines per file | no | no |
2024-11-02 14:23:46 -03:00
| [`filename-format` ](./RULES_DESCRIPTIONS.md#filename-format ) | regular expression (optional) | Enforces the formatting of filenames | no | no |
2024-11-20 21:26:28 +02:00
| [`redundant-build-tag` ](./RULES_DESCRIPTIONS.md#redundant-build-tag ) | n/a | Warns about redundant `// +build` comment lines | no | no |
2024-11-22 08:22:51 +01:00
| [`use-errors-new` ](./RULES_DESCRIPTIONS.md#use-errors-new ) | n/a | Spots calls to `fmt.Errorf` that can be replaced by `errors.New` | no | no |
2022-10-29 23:02:42 +05:30
2018-09-15 14:33:28 -07:00
## Configurable rules
2021-10-14 20:56:29 +02:00
Here you can find how you can configure some existing rules:
2018-09-15 14:33:28 -07:00
### `var-naming`
2024-02-03 18:36:44 +01:00
This rule accepts two slices of strings, an allowlist and a blocklist of initialisms. By default, the rule behaves exactly as the alternative in `golint` but optionally, you can relax it (see [golint/lint/issues/89 ](https://github.com/golang/lint/issues/89 ))
2018-09-15 14:33:28 -07:00
```toml
[rule.var-naming]
arguments = [["ID"], ["VM"]]
```
2024-07-11 11:26:42 +03:30
This way, revive will not warn for an identifier called `customId` but will warn that `customVm` should be called `customVM` .
2018-09-15 14:33:28 -07:00
2018-02-18 22:40:53 -08:00
## Available Formatters
This section lists all the available formatters and provides a screenshot for each one.
2018-05-26 14:12:02 -07:00
### Friendly
2018-10-30 16:07:32 -07:00
![Friendly formatter ](/assets/formatter-friendly.png )
2018-05-26 14:12:02 -07:00
2018-05-26 12:08:02 -07:00
### Stylish
2018-02-18 22:40:53 -08:00
2018-10-30 16:07:32 -07:00
![Stylish formatter ](/assets/formatter-stylish.png )
2018-02-18 22:40:53 -08:00
2018-05-26 14:12:02 -07:00
### Default
2018-10-30 16:07:32 -07:00
The default formatter produces the same output as `golint` .
![Default formatter ](/assets/formatter-default.png )
### Plain
2024-07-11 11:26:42 +03:30
The plain formatter produces the same output as the default formatter and appends the URL to the rule description.
2018-10-30 16:07:32 -07:00
![Plain formatter ](/assets/formatter-plain.png )
### Unix
The unix formatter produces the same output as the default formatter but surrounds the rules in `[]` .
![Unix formatter ](/assets/formatter-unix.png )
2018-05-26 14:12:02 -07:00
2024-11-22 09:21:43 +02:00
### JSON
The `json` formatter produces output in JSON format.
### NDJSON
The `ndjson` formatter produces output in [`Newline Delimited JSON` ](https://github.com/ndjson/ndjson-spec ) format.
### Checkstyle
The `checkstyle` formatter produces output in a [Checkstyle-like ](https://checkstyle.sourceforge.io/ ) format.
2021-04-05 20:54:33 +02:00
### SARIF
2024-10-25 15:34:38 +03:00
2024-11-22 09:21:43 +02:00
The `sarif` formatter produces output in SARIF, for _Static Analysis Results Interchange Format_ , a standard JSON-based format for the output of static analysis tools defined and promoted by [OASIS ](https://www.oasis-open.org/ ).
2021-04-05 20:54:33 +02:00
Current supported version of the standard is [SARIF-v2.1.0](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html
).
2018-05-26 15:17:28 -07:00
## Extensibility
2018-02-04 15:40:39 -08:00
The tool can be extended with custom rules or formatters. This section contains additional information on how to implement such.
2022-03-20 12:53:57 +01:00
To extend the linter with a custom rule you can push it to this repository or use `revive` as a library (see below)
2018-02-04 15:40:39 -08:00
2022-03-20 12:53:57 +01:00
To add a custom formatter you'll have to push it to this repository or fork it. This is due to the limited `-buildmode=plugin` support which [works only on Linux (with known issues) ](https://golang.org/pkg/plugin/ ).
### Writing a Custom Rule
2018-02-04 15:40:39 -08:00
Each rule needs to implement the `lint.Rule` interface:
```go
type Rule interface {
Name() string
Apply(*File, Arguments) []Failure
}
```
2018-02-18 22:19:37 -08:00
The `Arguments` type is an alias of the type `[]interface{}` . The arguments of the rule are passed from the configuration file.
#### Example
2024-07-11 11:26:42 +03:30
Let's suppose we have developed a rule called `BanStructNameRule` which disallow us to name a structure with a given identifier. We can set the banned identifier by using the TOML configuration file:
2018-02-04 15:40:39 -08:00
```toml
[rule.ban-struct-name]
2018-02-04 15:41:22 -08:00
arguments = ["Foo"]
2018-02-04 15:40:39 -08:00
```
With the snippet above we:
2024-07-11 11:26:42 +03:30
- Enable the rule with the name `ban-struct-name` . The `Name()` method of our rule should return a string that matches `ban-struct-name` .
2018-06-08 10:28:17 -07:00
- Configure the rule with the argument `Foo` . The list of arguments will be passed to `Apply(*File, Arguments)` together with the target file we're linting currently.
2018-02-04 15:40:39 -08:00
2024-12-01 13:56:34 +02:00
A sample rule implementation can be found [here ](/rule/argument_limit.go ).
2018-02-04 15:40:39 -08:00
2022-03-20 12:53:57 +01:00
#### Using `revive` as a library
2024-10-25 15:34:38 +03:00
2023-10-27 07:26:27 +02:00
If a rule is specific to your use case
2024-07-11 11:26:42 +03:30
(i.e. it is not a good candidate to be added to `revive` 's rule set) you can add it to your linter using `revive` as a linting engine.
2022-03-20 12:53:57 +01:00
2024-07-11 11:26:42 +03:30
The following code shows how to use `revive` in your application.
2023-10-27 07:26:27 +02:00
In the example only one rule is added (`myRule` ), of course, you can add as many as you need to.
2022-03-20 12:53:57 +01:00
Your rules can be configured programmatically or with the standard `revive` configuration file.
The full rule set of `revive` is also actionable by your application.
```go
package main
import (
"github.com/mgechev/revive/cli"
"github.com/mgechev/revive/lint"
2022-03-29 17:30:36 -03:00
"github.com/mgechev/revive/revivelib"
2022-03-20 12:53:57 +01:00
)
func main() {
2022-03-29 12:31:52 -03:00
cli.RunRevive(revivelib.NewExtraRule(& myRule{}, lint.RuleConfig{}))
}
type myRule struct{}
func (f myRule) Name() string {
return "myRule"
}
func (f myRule) Apply(*lint.File, lint.Arguments) []lint.Failure { ... }
```
2024-07-11 11:26:42 +03:30
You can still go further and use `revive` without its CLI, as part of your library, or your CLI:
2022-03-29 12:31:52 -03:00
```go
package mylib
import (
"github.com/mgechev/revive/cli"
"github.com/mgechev/revive/revivelib"
"github.com/mgechev/revive/lint"
)
// Error checking removed for clarity
func LintMyFile(file string) {
conf, _:= config.GetConfig("../defaults.toml")
revive, _ := revivelib.New(
conf, // Configuration file
true, // Set exit status
2048, // Max open files
2022-03-29 17:30:36 -03:00
// Then add as many extra rules as you need
2022-03-29 12:31:52 -03:00
revivelib.NewExtraRule(& myRule{}, lint.RuleConfig{}),
)
failuresChan, err := revive.Lint(
revivelib.Include(file),
revivelib.Exclude("./fixtures"),
// You can use as many revivelib.Include or revivelib.Exclude as required
)
if err != nil {
2024-11-14 12:45:07 +02:00
panic("Shouldn't have failed: " + err.Error())
2022-03-29 12:31:52 -03:00
}
// Now let's return the formatted errors
failures, exitCode, _ := revive.Format("stylish", failuresChan)
// failures is the string with all formatted lint error messages
// exit code is 0 if no errors, 1 if errors (unless config options change it)
// ... do something with them
2022-03-20 12:53:57 +01:00
}
type myRule struct{}
func (f myRule) Name() string {
return "myRule"
}
func (f myRule) Apply(*lint.File, lint.Arguments) []lint.Failure { ... }
```
2018-02-04 15:40:39 -08:00
### Custom Formatter
Each formatter needs to implement the following interface:
```go
type Formatter interface {
2019-08-02 17:21:33 +02:00
Format(< -chan Failure , Config ) ( string , error )
2018-02-04 15:40:39 -08:00
Name() string
}
```
2018-02-18 22:19:37 -08:00
The `Format` method accepts a channel of `Failure` instances and the configuration of the enabled rules. The `Name()` method should return a string different from the names of the already existing rules. This string is used when specifying the formatter when invoking the `revive` CLI tool.
2018-02-04 15:40:39 -08:00
For a sample formatter, take a look at [this file ](/formatter/json.go ).
2018-05-26 19:13:54 -07:00
## Speed Comparison
2024-07-11 11:26:42 +03:30
Compared to `golint` , `revive` performs better because it lints the files for each individual rule into a separate goroutine. Here's a basic performance benchmark on MacBook Pro Early 2013 run on Kubernetes:
2018-05-26 19:13:54 -07:00
### golint
```shell
time golint kubernetes/... > /dev/null
real 0m54.837s
user 0m57.844s
sys 0m9.146s
```
2024-10-25 15:34:38 +03:00
### revive's speed
2018-05-26 19:13:54 -07:00
```shell
2018-05-31 20:00:04 -07:00
# no type checking
2018-05-31 21:14:00 -07:00
time revive -config untyped.toml kubernetes/... > /dev/null
2018-05-26 19:13:54 -07:00
2018-05-31 21:14:00 -07:00
real 0m8.471s
user 0m40.721s
sys 0m3.262s
2018-05-26 19:13:54 -07:00
```
2024-07-11 11:26:42 +03:30
Keep in mind that if you use rules that require type checking, the performance may drop to 2x faster than `golint` :
2018-05-31 19:53:26 -07:00
```shell
2018-05-31 20:00:04 -07:00
# type checking enabled
2018-05-31 19:53:26 -07:00
time revive kubernetes/... > /dev/null
real 0m26.211s
user 2m6.708s
sys 0m17.192s
```
2024-07-11 11:26:42 +03:30
Currently, type-checking is enabled by default. If you want to run the linter without type-checking, remove all typed rules from the configuration file.
2018-05-31 19:53:26 -07:00
2020-05-14 23:08:30 +02:00
## Overriding colorization detection
By default, `revive` determines whether or not to colorize its output based on whether it's connected to a TTY or not.
This works for most use cases, but may not behave as expected if you use `revive` in a pipeline of commands,
where STDOUT is being piped to another command.
To force colorization, add `REVIVE_FORCE_COLOR=1` to the environment you're running in. For example:
```shell
REVIVE_FORCE_COLOR=1 revive -formatter friendly ./... | tee revive.log
```
2018-06-08 10:24:28 -07:00
## Contributors
2024-11-04 14:22:08 +02:00
[<img alt="mgechev" src="https://avatars.githubusercontent.com/u/455023?v=4&s=117" width="117"> ](https://github.com/mgechev ) |[<img alt="chavacava" src="https://avatars.githubusercontent.com/u/25788468?v=4&s=117" width="117"> ](https://github.com/chavacava ) |[<img alt="denisvmedia" src="https://avatars.githubusercontent.com/u/5462781?v=4&s=117" width="117"> ](https://github.com/denisvmedia ) |[<img alt="mfederowicz" src="https://avatars.githubusercontent.com/u/57678185?v=4&s=117" width="117"> ](https://github.com/mfederowicz ) |[<img alt="xuri" src="https://avatars.githubusercontent.com/u/2809468?v=4&s=117" width="117"> ](https://github.com/xuri ) |[<img alt="alexandear" src="https://avatars.githubusercontent.com/u/3228886?v=4&s=117" width="117"> ](https://github.com/alexandear ) |
2021-06-02 10:41:53 -07:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[mgechev ](https://github.com/mgechev ) |[chavacava ](https://github.com/chavacava ) |[denisvmedia ](https://github.com/denisvmedia ) |[mfederowicz ](https://github.com/mfederowicz ) |[xuri ](https://github.com/xuri ) |[alexandear ](https://github.com/alexandear ) |
2021-06-02 10:41:53 -07:00
2024-11-04 14:22:08 +02:00
[<img alt="ldez" src="https://avatars.githubusercontent.com/u/5674651?v=4&s=117" width="117"> ](https://github.com/ldez ) |[<img alt="doniacld" src="https://avatars.githubusercontent.com/u/19799268?v=4&s=117" width="117"> ](https://github.com/doniacld ) |[<img alt="Clivern" src="https://avatars.githubusercontent.com/u/1634427?v=4&s=117" width="117"> ](https://github.com/Clivern ) |[<img alt="morphy2k" src="https://avatars.githubusercontent.com/u/4280578?v=4&s=117" width="117"> ](https://github.com/morphy2k ) |[<img alt="bernhardreisenberger" src="https://avatars.githubusercontent.com/u/5809300?v=4&s=117" width="117"> ](https://github.com/bernhardreisenberger ) |[<img alt="dshemin" src="https://avatars.githubusercontent.com/u/11780307?v=4&s=117" width="117"> ](https://github.com/dshemin ) |
2018-09-08 17:48:14 -07:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[ldez ](https://github.com/ldez ) |[doniacld ](https://github.com/doniacld ) |[Clivern ](https://github.com/Clivern ) |[morphy2k ](https://github.com/morphy2k ) |[bernhardreisenberger ](https://github.com/bernhardreisenberger ) |[dshemin ](https://github.com/dshemin ) |
2018-07-20 16:56:37 -07:00
2024-11-04 14:22:08 +02:00
[<img alt="butuzov" src="https://avatars.githubusercontent.com/u/651824?v=4&s=117" width="117"> ](https://github.com/butuzov ) |[<img alt="comdiv" src="https://avatars.githubusercontent.com/u/2387862?v=4&s=117" width="117"> ](https://github.com/comdiv ) |[<img alt="heynemann" src="https://avatars.githubusercontent.com/u/60965?v=4&s=117" width="117"> ](https://github.com/heynemann ) |[<img alt="gsamokovarov" src="https://avatars.githubusercontent.com/u/604618?v=4&s=117" width="117"> ](https://github.com/gsamokovarov ) |[<img alt="mdelah" src="https://avatars.githubusercontent.com/u/4904544?v=4&s=117" width="117"> ](https://github.com/mdelah ) |[<img alt="tymonx" src="https://avatars.githubusercontent.com/u/8367378?v=4&s=117" width="117"> ](https://github.com/tymonx ) |
2018-10-17 10:07:33 -07:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[butuzov ](https://github.com/butuzov ) |[comdiv ](https://github.com/comdiv ) |[heynemann ](https://github.com/heynemann ) |[gsamokovarov ](https://github.com/gsamokovarov ) |[mdelah ](https://github.com/mdelah ) |[tymonx ](https://github.com/tymonx ) |
2019-03-01 11:45:22 -08:00
2024-11-04 14:22:08 +02:00
[<img alt="sina-devel" src="https://avatars.githubusercontent.com/u/61763643?v=4&s=117" width="117"> ](https://github.com/sina-devel ) |[<img alt="rawen17" src="https://avatars.githubusercontent.com/u/36483900?v=4&s=117" width="117"> ](https://github.com/rawen17 ) |[<img alt="dominiquelefevre" src="https://avatars.githubusercontent.com/u/54854047?v=4&s=117" width="117"> ](https://github.com/dominiquelefevre ) |[<img alt="git-hulk" src="https://avatars.githubusercontent.com/u/4987594?v=4&s=117" width="117"> ](https://github.com/git-hulk ) |[<img alt="shmsr" src="https://avatars.githubusercontent.com/u/51480165?v=4&s=117" width="117"> ](https://github.com/shmsr ) |[<img alt="ytnsym" src="https://avatars.githubusercontent.com/u/57400690?v=4&s=117" width="117"> ](https://github.com/ytnsym ) |
2019-05-04 19:35:21 -06:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[sina-devel ](https://github.com/sina-devel ) |[rawen17 ](https://github.com/rawen17 ) |[dominiquelefevre ](https://github.com/dominiquelefevre ) |[git-hulk ](https://github.com/git-hulk ) |[shmsr ](https://github.com/shmsr ) |[ytnsym ](https://github.com/ytnsym ) |
2019-09-16 12:31:59 -07:00
2024-11-04 14:22:08 +02:00
[<img alt="zimmski" src="https://avatars.githubusercontent.com/u/1847950?v=4&s=117" width="117"> ](https://github.com/zimmski ) |[<img alt="mapreal19" src="https://avatars.githubusercontent.com/u/3055997?v=4&s=117" width="117"> ](https://github.com/mapreal19 ) |[<img alt="cce" src="https://avatars.githubusercontent.com/u/51567?v=4&s=117" width="117"> ](https://github.com/cce ) |[<img alt="skaji" src="https://avatars.githubusercontent.com/u/1589550?v=4&s=117" width="117"> ](https://github.com/skaji ) |[<img alt="ccoVeille" src="https://avatars.githubusercontent.com/u/3875889?v=4&s=117" width="117"> ](https://github.com/ccoVeille ) |[<img alt="tamird" src="https://avatars.githubusercontent.com/u/1535036?v=4&s=117" width="117"> ](https://github.com/tamird ) |
2020-08-03 17:29:08 +03:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[zimmski ](https://github.com/zimmski ) |[mapreal19 ](https://github.com/mapreal19 ) |[cce ](https://github.com/cce ) |[skaji ](https://github.com/skaji ) |[ccoVeille ](https://github.com/ccoVeille ) |[tamird ](https://github.com/tamird ) |
2020-08-03 17:29:08 +03:00
2024-11-04 14:22:08 +02:00
[<img alt="markelog" src="https://avatars.githubusercontent.com/u/945528?v=4&s=117" width="117"> ](https://github.com/markelog ) |[<img alt="mihaitodor" src="https://avatars.githubusercontent.com/u/788216?v=4&s=117" width="117"> ](https://github.com/mihaitodor ) |[<img alt="dvejmz" src="https://avatars.githubusercontent.com/u/9487006?v=4&s=117" width="117"> ](https://github.com/dvejmz ) |[<img alt="abeltay" src="https://avatars.githubusercontent.com/u/15604207?v=4&s=117" width="117"> ](https://github.com/abeltay ) |[<img alt="damif94" src="https://avatars.githubusercontent.com/u/29461526?v=4&s=117" width="117"> ](https://github.com/damif94 ) |[<img alt="Groxx" src="https://avatars.githubusercontent.com/u/77197?v=4&s=117" width="117"> ](https://github.com/Groxx ) |
2021-07-11 21:35:26 -07:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[markelog ](https://github.com/markelog ) |[mihaitodor ](https://github.com/mihaitodor ) |[dvejmz ](https://github.com/dvejmz ) |[abeltay ](https://github.com/abeltay ) |[damif94 ](https://github.com/damif94 ) |[Groxx ](https://github.com/Groxx ) |
2018-06-08 10:24:28 -07:00
2024-11-04 14:22:08 +02:00
[<img alt="StephenButtolph" src="https://avatars.githubusercontent.com/u/22109487?v=4&s=117" width="117"> ](https://github.com/StephenButtolph ) |[<img alt="StephenBrown2" src="https://avatars.githubusercontent.com/u/1148665?v=4&s=117" width="117"> ](https://github.com/StephenBrown2 ) |[<img alt="lsytj0413" src="https://avatars.githubusercontent.com/u/6871552?v=4&s=117" width="117"> ](https://github.com/lsytj0413 ) |[<img alt="qascade" src="https://avatars.githubusercontent.com/u/54154054?v=4&s=117" width="117"> ](https://github.com/qascade ) |[<img alt="ridvansumset" src="https://avatars.githubusercontent.com/u/26631560?v=4&s=117" width="117"> ](https://github.com/ridvansumset ) |[<img alt="rliebz" src="https://avatars.githubusercontent.com/u/5321575?v=4&s=117" width="117"> ](https://github.com/rliebz ) |
2022-03-29 13:34:37 -07:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[StephenButtolph ](https://github.com/StephenButtolph ) |[StephenBrown2 ](https://github.com/StephenBrown2 ) |[lsytj0413 ](https://github.com/lsytj0413 ) |[qascade ](https://github.com/qascade ) |[ridvansumset ](https://github.com/ridvansumset ) |[rliebz ](https://github.com/rliebz ) |
2022-03-29 12:31:52 -03:00
2024-11-04 14:22:08 +02:00
[<img alt="rdeusser" src="https://avatars.githubusercontent.com/u/5935071?v=4&s=117" width="117"> ](https://github.com/rdeusser ) |[<img alt="rmarku" src="https://avatars.githubusercontent.com/u/1113370?v=4&s=117" width="117"> ](https://github.com/rmarku ) |[<img alt="rnikoopour" src="https://avatars.githubusercontent.com/u/7692789?v=4&s=117" width="117"> ](https://github.com/rnikoopour ) |[<img alt="rafamadriz" src="https://avatars.githubusercontent.com/u/67771985?v=4&s=117" width="117"> ](https://github.com/rafamadriz ) |[<img alt="paco0x" src="https://avatars.githubusercontent.com/u/6123425?v=4&s=117" width="117"> ](https://github.com/paco0x ) |[<img alt="pa-m" src="https://avatars.githubusercontent.com/u/5503106?v=4&s=117" width="117"> ](https://github.com/pa-m ) |
2022-03-29 13:34:37 -07:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[rdeusser ](https://github.com/rdeusser ) |[rmarku ](https://github.com/rmarku ) |[rnikoopour ](https://github.com/rnikoopour ) |[rafamadriz ](https://github.com/rafamadriz ) |[paco0x ](https://github.com/paco0x ) |[pa-m ](https://github.com/pa-m ) |
2022-03-29 12:31:52 -03:00
2024-11-04 14:22:08 +02:00
[<img alt="cinar" src="https://avatars.githubusercontent.com/u/1754092?v=4&s=117" width="117"> ](https://github.com/cinar ) |[<img alt="natefinch" src="https://avatars.githubusercontent.com/u/3185864?v=4&s=117" width="117"> ](https://github.com/natefinch ) |[<img alt="nunnatsa" src="https://avatars.githubusercontent.com/u/60659093?v=4&s=117" width="117"> ](https://github.com/nunnatsa ) |[<img alt="michalhisim" src="https://avatars.githubusercontent.com/u/764249?v=4&s=117" width="117"> ](https://github.com/michalhisim ) |[<img alt="zeripath" src="https://avatars.githubusercontent.com/u/1824502?v=4&s=117" width="117"> ](https://github.com/zeripath ) |[<img alt="y-yagi" src="https://avatars.githubusercontent.com/u/987638?v=4&s=117" width="117"> ](https://github.com/y-yagi ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[cinar ](https://github.com/cinar ) |[natefinch ](https://github.com/natefinch ) |[nunnatsa ](https://github.com/nunnatsa ) |[michalhisim ](https://github.com/michalhisim ) |[zeripath ](https://github.com/zeripath ) |[y-yagi ](https://github.com/y-yagi ) |
2024-01-08 10:00:05 +01:00
2024-11-04 14:22:08 +02:00
[<img alt="techknowlogick" src="https://avatars.githubusercontent.com/u/164197?v=4&s=117" width="117"> ](https://github.com/techknowlogick ) |[<img alt="okhowang" src="https://avatars.githubusercontent.com/u/3352585?v=4&s=117" width="117"> ](https://github.com/okhowang ) |[<img alt="meanguy" src="https://avatars.githubusercontent.com/u/78570571?v=4&s=117" width="117"> ](https://github.com/meanguy ) |[<img alt="likyh" src="https://avatars.githubusercontent.com/u/3294100?v=4&s=117" width="117"> ](https://github.com/likyh ) |[<img alt="kerneltravel" src="https://avatars.githubusercontent.com/u/437879?v=4&s=117" width="117"> ](https://github.com/kerneltravel ) |[<img alt="jmckenzieark" src="https://avatars.githubusercontent.com/u/70923399?v=4&s=117" width="117"> ](https://github.com/jmckenzieark ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[techknowlogick ](https://github.com/techknowlogick ) |[okhowang ](https://github.com/okhowang ) |[meanguy ](https://github.com/meanguy ) |[likyh ](https://github.com/likyh ) |[kerneltravel ](https://github.com/kerneltravel ) |[jmckenzieark ](https://github.com/jmckenzieark ) |
2024-01-08 10:00:05 +01:00
2024-11-04 14:22:08 +02:00
[<img alt="haya14busa" src="https://avatars.githubusercontent.com/u/3797062?v=4&s=117" width="117"> ](https://github.com/haya14busa ) |[<img alt="fregin" src="https://avatars.githubusercontent.com/u/23256240?v=4&s=117" width="117"> ](https://github.com/fregin ) |[<img alt="ydah" src="https://avatars.githubusercontent.com/u/13041216?v=4&s=117" width="117"> ](https://github.com/ydah ) |[<img alt="WillAbides" src="https://avatars.githubusercontent.com/u/233500?v=4&s=117" width="117"> ](https://github.com/WillAbides ) |[<img alt="heyvito" src="https://avatars.githubusercontent.com/u/77198?v=4&s=117" width="117"> ](https://github.com/heyvito ) |[<img alt="VincentBaron" src="https://avatars.githubusercontent.com/u/58427099?v=4&s=117" width="117"> ](https://github.com/VincentBaron ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[haya14busa ](https://github.com/haya14busa ) |[fregin ](https://github.com/fregin ) |[ydah ](https://github.com/ydah ) |[WillAbides ](https://github.com/WillAbides ) |[heyvito ](https://github.com/heyvito ) |[VincentBaron ](https://github.com/VincentBaron ) |
2024-01-08 10:00:05 +01:00
2024-11-04 14:22:08 +02:00
[<img alt="scop" src="https://avatars.githubusercontent.com/u/109152?v=4&s=117" width="117"> ](https://github.com/scop ) |[<img alt="vkrol" src="https://avatars.githubusercontent.com/u/153412?v=4&s=117" width="117"> ](https://github.com/vkrol ) |[<img alt="KirillSluchaev" src="https://avatars.githubusercontent.com/u/58340009?v=4&s=117" width="117"> ](https://github.com/KirillSluchaev ) |[<img alt="Jarema" src="https://avatars.githubusercontent.com/u/7369771?v=4&s=117" width="117"> ](https://github.com/Jarema ) |[<img alt="tartale" src="https://avatars.githubusercontent.com/u/9323250?v=4&s=117" width="117"> ](https://github.com/tartale ) |[<img alt="tmzane" src="https://avatars.githubusercontent.com/u/73077675?v=4&s=117" width="117"> ](https://github.com/tmzane ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[scop ](https://github.com/scop ) |[vkrol ](https://github.com/vkrol ) |[KirillSluchaev ](https://github.com/KirillSluchaev ) |[Jarema ](https://github.com/Jarema ) |[tartale ](https://github.com/tartale ) |[tmzane ](https://github.com/tmzane ) |
[<img alt="felipedavid" src="https://avatars.githubusercontent.com/u/75049173?v=4&s=117" width="117"> ](https://github.com/felipedavid ) |[<img alt="euank" src="https://avatars.githubusercontent.com/u/2147649?v=4&s=117" width="117"> ](https://github.com/euank ) |[<img alt="Entuazism" src="https://avatars.githubusercontent.com/u/56657856?v=4&s=117" width="117"> ](https://github.com/Entuazism ) |[<img alt="Juneezee" src="https://avatars.githubusercontent.com/u/20135478?v=4&s=117" width="117"> ](https://github.com/Juneezee ) |[<img alt="echoix" src="https://avatars.githubusercontent.com/u/27212526?v=4&s=117" width="117"> ](https://github.com/echoix ) |[<img alt="EXHades" src="https://avatars.githubusercontent.com/u/22260242?v=4&s=117" width="117"> ](https://github.com/EXHades ) |
:---: |:---: |:---: |:---: |:---: |:---: |
[felipedavid ](https://github.com/felipedavid ) |[euank ](https://github.com/euank ) |[Entuazism ](https://github.com/Entuazism ) |[Juneezee ](https://github.com/Juneezee ) |[echoix ](https://github.com/echoix ) |[EXHades ](https://github.com/EXHades ) |
2024-01-08 10:00:05 +01:00
[<img alt="petethepig" src="https://avatars.githubusercontent.com/u/662636?v=4&s=117" width="117"> ](https://github.com/petethepig ) |[<img alt="Dirk007" src="https://avatars.githubusercontent.com/u/17194484?v=4&s=117" width="117"> ](https://github.com/Dirk007 ) |[<img alt="yangdiangzb" src="https://avatars.githubusercontent.com/u/16643665?v=4&s=117" width="117"> ](https://github.com/yangdiangzb ) |[<img alt="derekperkins" src="https://avatars.githubusercontent.com/u/3588778?v=4&s=117" width="117"> ](https://github.com/derekperkins ) |[<img alt="bboreham" src="https://avatars.githubusercontent.com/u/8125524?v=4&s=117" width="117"> ](https://github.com/bboreham ) |[<img alt="attiss" src="https://avatars.githubusercontent.com/u/23562566?v=4&s=117" width="117"> ](https://github.com/attiss ) |
:---: |:---: |:---: |:---: |:---: |:---: |
[petethepig ](https://github.com/petethepig ) |[Dirk007 ](https://github.com/Dirk007 ) |[yangdiangzb ](https://github.com/yangdiangzb ) |[derekperkins ](https://github.com/derekperkins ) |[bboreham ](https://github.com/bboreham ) |[attiss ](https://github.com/attiss ) |
2024-11-04 14:22:08 +02:00
[<img alt="hatamiarash7" src="https://avatars.githubusercontent.com/u/16325641?v=4&s=117" width="117"> ](https://github.com/hatamiarash7 ) |[<img alt="Aragur" src="https://avatars.githubusercontent.com/u/11004008?v=4&s=117" width="117"> ](https://github.com/Aragur ) |[<img alt="amincheloh" src="https://avatars.githubusercontent.com/u/1217397?v=4&s=117" width="117"> ](https://github.com/amincheloh ) |[<img alt="kulti" src="https://avatars.githubusercontent.com/u/1286683?v=4&s=117" width="117"> ](https://github.com/kulti ) |[<img alt="Abirdcfly" src="https://avatars.githubusercontent.com/u/5100555?v=4&s=117" width="117"> ](https://github.com/Abirdcfly ) |[<img alt="abhinav" src="https://avatars.githubusercontent.com/u/41730?v=4&s=117" width="117"> ](https://github.com/abhinav ) |
:---: |:---: |:---: |:---: |:---: |:---: |
[hatamiarash7 ](https://github.com/hatamiarash7 ) |[Aragur ](https://github.com/Aragur ) |[amincheloh ](https://github.com/amincheloh ) |[kulti ](https://github.com/kulti ) |[Abirdcfly ](https://github.com/Abirdcfly ) |[abhinav ](https://github.com/abhinav ) |
[<img alt="r-ricci" src="https://avatars.githubusercontent.com/u/52817765?v=4&s=117" width="117"> ](https://github.com/r-ricci ) |[<img alt="mmcloughlin" src="https://avatars.githubusercontent.com/u/7133685?v=4&s=117" width="117"> ](https://github.com/mmcloughlin ) |[<img alt="mathieu-aubin" src="https://avatars.githubusercontent.com/u/15820228?v=4&s=117" width="117"> ](https://github.com/mathieu-aubin ) |[<img alt="martinsirbe" src="https://avatars.githubusercontent.com/u/13367583?v=4&s=117" width="117"> ](https://github.com/martinsirbe ) |[<img alt="avorima" src="https://avatars.githubusercontent.com/u/15158349?v=4&s=117" width="117"> ](https://github.com/avorima ) |[<img alt="moukoublen" src="https://avatars.githubusercontent.com/u/1380039?v=4&s=117" width="117"> ](https://github.com/moukoublen ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[r-ricci ](https://github.com/r-ricci ) |[mmcloughlin ](https://github.com/mmcloughlin ) |[mathieu-aubin ](https://github.com/mathieu-aubin ) |[martinsirbe ](https://github.com/martinsirbe ) |[avorima ](https://github.com/avorima ) |[moukoublen ](https://github.com/moukoublen ) |
2024-01-08 10:00:05 +01:00
2024-11-04 14:22:08 +02:00
[<img alt="very-amused" src="https://avatars.githubusercontent.com/u/44382255?v=4&s=117" width="117"> ](https://github.com/very-amused ) |[<img alt="johnrichardrinehart" src="https://avatars.githubusercontent.com/u/6321578?v=4&s=117" width="117"> ](https://github.com/johnrichardrinehart ) |[<img alt="walles" src="https://avatars.githubusercontent.com/u/158201?v=4&s=117" width="117"> ](https://github.com/walles ) |[<img alt="jefersonf" src="https://avatars.githubusercontent.com/u/3049540?v=4&s=117" width="117"> ](https://github.com/jefersonf ) |[<img alt="jamesmaidment" src="https://avatars.githubusercontent.com/u/2050324?v=4&s=117" width="117"> ](https://github.com/jamesmaidment ) |[<img alt="jalaziz" src="https://avatars.githubusercontent.com/u/247849?v=4&s=117" width="117"> ](https://github.com/jalaziz ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[very-amused ](https://github.com/very-amused ) |[johnrichardrinehart ](https://github.com/johnrichardrinehart ) |[walles ](https://github.com/walles ) |[jefersonf ](https://github.com/jefersonf ) |[jamesmaidment ](https://github.com/jamesmaidment ) |[jalaziz ](https://github.com/jalaziz ) |
2024-01-08 10:00:05 +01:00
2024-11-04 14:22:08 +02:00
[<img alt="grongor" src="https://avatars.githubusercontent.com/u/972493?v=4&s=117" width="117"> ](https://github.com/grongor ) |[<img alt="tie" src="https://avatars.githubusercontent.com/u/14792994?v=4&s=117" width="117"> ](https://github.com/tie ) |[<img alt="quasilyte" src="https://avatars.githubusercontent.com/u/6286655?v=4&s=117" width="117"> ](https://github.com/quasilyte ) |[<img alt="davidhsingyuchen" src="https://avatars.githubusercontent.com/u/17587061?v=4&s=117" width="117"> ](https://github.com/davidhsingyuchen ) |[<img alt="gfariasalves-ionos" src="https://avatars.githubusercontent.com/u/112630064?v=4&s=117" width="117"> ](https://github.com/gfariasalves-ionos ) |[<img alt="gburanov" src="https://avatars.githubusercontent.com/u/2969603?v=4&s=117" width="117"> ](https://github.com/gburanov ) |
2024-01-08 10:00:05 +01:00
:---: |:---: |:---: |:---: |:---: |:---: |
2024-11-04 14:22:08 +02:00
[grongor ](https://github.com/grongor ) |[tie ](https://github.com/tie ) |[quasilyte ](https://github.com/quasilyte ) |[davidhsingyuchen ](https://github.com/davidhsingyuchen ) |[gfariasalves-ionos ](https://github.com/gfariasalves-ionos ) |[gburanov ](https://github.com/gburanov ) |
2024-01-08 10:00:05 +01:00
2024-11-04 14:22:08 +02:00
[<img alt="ginglis13" src="https://avatars.githubusercontent.com/u/43075615?v=4&s=117" width="117"> ](https://github.com/ginglis13 ) |[<img alt="flesser" src="https://avatars.githubusercontent.com/u/510681?v=4&s=117" width="117"> ](https://github.com/flesser ) |
:---: |:---: |
[ginglis13 ](https://github.com/ginglis13 ) |[flesser ](https://github.com/flesser ) |
2022-03-29 12:31:52 -03:00
2018-02-04 12:19:24 -08:00
## License
2017-08-27 20:57:46 -07:00
MIT