{"id":13491235,"url":"https://github.com/mgechev/revive","last_synced_at":"2025-09-09T21:16:19.954Z","repository":{"id":37389496,"uuid":"96237042","full_name":"mgechev/revive","owner":"mgechev","description":"🔥 ~6x faster, stricter, configurable, extensible, and beautiful drop-in replacement for golint","archived":false,"fork":false,"pushed_at":"2025-04-26T06:55:22.000Z","size":6343,"stargazers_count":5131,"open_issues_count":44,"forks_count":293,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-04-26T07:31:33.580Z","etag":null,"topics":["go","golang","golint","hacktoberfest","linter","static-analysis","static-code-analysis"],"latest_commit_sha":null,"homepage":"https://revive.run","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mgechev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-07-04T16:36:32.000Z","updated_at":"2025-04-25T10:23:12.000Z","dependencies_parsed_at":"2023-02-15T01:16:27.678Z","dependency_job_id":"532ac919-f4cc-4ae9-a02f-7a67be921542","html_url":"https://github.com/mgechev/revive","commit_stats":{"total_commits":776,"total_committers":86,"mean_commits":9.023255813953488,"dds":0.663659793814433,"last_synced_commit":"b03e54f617491984b41f0411b69326f94d03a76f"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgechev%2Frevive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgechev%2Frevive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgechev%2Frevive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgechev%2Frevive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mgechev","download_url":"https://codeload.github.com/mgechev/revive/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251293243,"owners_count":21566070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","golint","hacktoberfest","linter","static-analysis","static-code-analysis"],"created_at":"2024-07-31T19:00:54.773Z","updated_at":"2025-09-09T21:16:19.928Z","avatar_url":"https://github.com/mgechev.png","language":"Go","funding_links":[],"categories":["Go","Misc","开源类库","Code Analysis","Open source library","Containers \u0026 Language Extentions \u0026 Linting","Linters","代码分析","[](https://github.com/golang/go/wiki/CodeTools#code-formatting)Code Formatting","Repositories","Tooling"],"sub_categories":["代码分析","Routers","Code Analysis","For Go","Style and Patterns Checking","路由器","[](https://github.com/golang/go/wiki/CodeTools#tools)Tools","Advanced and Specialized Tools"],"readme":"# revive\n\n[![Build Status](https://github.com/mgechev/revive/actions/workflows/test.yaml/badge.svg)](https://github.com/mgechev/revive/actions/workflows/test.yaml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/mgechev/revive.svg)](https://pkg.go.dev/github.com/mgechev/revive)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/mgechev/revive)\n\nFast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.\n**`Revive` provides a framework for development of custom rules,\nand lets you define a strict preset for enhancing your development \u0026 code review processes**.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/logo.png\" alt=\"\" width=\"300\"\u003e\n  \u003cbr\u003e\n  Logo by \u003ca href=\"https://github.com/hawkgs\"\u003eGeorgi Serev\u003c/a\u003e\n\u003c/p\u003e\n\nHere's how `revive` is different from `golint`:\n\n- Allows to enable or disable rules using a configuration file.\n- Allows to configure the linting rules with a TOML file.\n- 2x faster running the same rules as golint.\n- Provides functionality for disabling a specific rule or the entire linter for a file or a range of lines.\n  - `golint` allows this only for generated files.\n- Optional type checking. Most rules in golint do not require type checking.\nIf you disable them in the config file, revive will run over 6x faster than golint.\n- Provides multiple formatters which let us customize the output.\n- Allows to customize the return code for the entire linter or based on the failure of only some rules.\n- _Everyone can extend it easily with custom rules or formatters._\n- `Revive` provides more rules compared to `golint`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/demo.svg\" alt=\"\" width=\"700\"\u003e\n\u003c/p\u003e\n\n\u003c!-- toc --\u003e\n\n- [Installation](#installation)\n  - [Homebrew](#homebrew)\n  - [Install from Sources](#install-from-sources)\n  - [Docker](#docker)\n  - [Manual Binary Download](#manual-binary-download)\n- [Usage](#usage)\n  - [Bazel](#bazel)\n  - [Text Editors](#text-editors)\n  - [GitHub Actions](#github-actions)\n  - [Continuous Integration](#continuous-integration)\n  - [Linter aggregators](#linter-aggregators)\n    - [golangci-lint](#golangci-lint)\n  - [Command Line Flags](#command-line-flags)\n  - [Sample Invocations](#sample-invocations)\n  - [Comment Directives](#comment-directives)\n  - [Configuration](#configuration)\n  - [Default Configuration](#default-configuration)\n  - [Custom Configuration](#custom-configuration)\n  - [Recommended Configuration](#recommended-configuration)\n  - [Rule-level file excludes](#rule-level-file-excludes)\n- [Available Rules](#available-rules)\n- [Configurable rules](#configurable-rules)\n  - [`var-naming`](#var-naming)\n- [Available Formatters](#available-formatters)\n  - [Friendly](#friendly)\n  - [Stylish](#stylish)\n  - [Default](#default)\n  - [Plain](#plain)\n  - [Unix](#unix)\n  - [JSON](#json)\n  - [NDJSON](#ndjson)\n  - [Checkstyle](#checkstyle)\n  - [SARIF](#sarif)\n- [Extensibility](#extensibility)\n  - [Writing a Custom Rule](#writing-a-custom-rule)\n    - [Using `revive` as a library](#using-revive-as-a-library)\n  - [Custom Formatter](#custom-formatter)\n- [Speed Comparison](#speed-comparison)\n  - [golint](#golint)\n  - [revive's speed](#revives-speed)\n- [Overriding colorization detection](#overriding-colorization-detection)\n- [Who uses Revive](#who-uses-revive)\n- [Contributors](#contributors)\n  - [Maintainers](#maintainers)\n  - [All](#all)\n- [License](#license)\n\n\u003c!-- tocstop --\u003e\n\n## Installation\n\n`revive` is available inside the majority of package managers.\n\n[\u003cimg alt=\"Repology packaging status\" src=\"https://repology.org/badge/vertical-allrepos/revive.svg\"\u003e](https://repology.org/project/revive/versions)\n\n### Homebrew\n\nInstall `revive` using [brew](https://brew.sh/):\n\n```bash\nbrew install revive\n```\n\nTo upgrade to the latest version:\n\n```bash\nbrew upgrade revive\n```\n\n### Install from Sources\n\nInstall the latest stable release directly from source:\n\n```bash\ngo install github.com/mgechev/revive@latest\n```\n\nTo install the latest commit from the main branch:\n\n```bash\ngo install github.com/mgechev/revive@HEAD\n```\n\n### Docker\n\nYou can run `revive` using Docker to avoid installing it directly on your system:\n\n```bash\ndocker run -v \"$(pwd)\":/var/YOUR_REPOSITORY ghcr.io/mgechev/revive:v1.10.0 -config /var/YOUR_REPOSITORY/revive.toml -formatter stylish ./var/YOUR_REPOSITORY/...\n```\n\n_Note_: Replace `YOUR_REPOSITORY` with the path to your repository.\n\nA volume must be mounted to share the current repository with the container.\nFor more details, refer to the [bind mounts Docker documentation](https://docs.docker.com/storage/bind-mounts/).\n\n- `-v`: Mounts the current directory (`$(pwd)`) to `/var/YOUR_REPOSITORY` inside the container.\n- `ghcr.io/mgechev/revive:v1.10.0`: Specifies the Docker image and its version.\n- `revive`: The command to run inside the container.\n- Flags like `-config` and `-formatter` are the same as when using the binary directly.\n\n### Manual Binary Download\n\nDownload the precompiled binary from the [Releases page](https://github.com/mgechev/revive/releases):\n\n1. Select the appropriate binary for your OS and architecture.\n2. Extract the binary and move it to a directory in your `PATH` (e.g., `/usr/local/bin`).\n3. Verify installation:\n\n```bash\nrevive -version\n```\n\n## Usage\n\nSince the default behavior of `revive` is compatible with `golint`, without providing any additional flags,\nthe only difference you'd notice is faster execution.\n\n`revive` supports a `-config` flag whose value should correspond to a TOML file describing which rules to use for `revive`'s linting.\nIf not provided, `revive` will try to use a global config file (assumed to be located at `$HOME/revive.toml`).\nOtherwise, if no configuration TOML file is found then `revive` uses a built-in set of default linting rules.\n\n### Bazel\n\nIf you want to use revive with Bazel, look at the [rules](https://github.com/atlassian/bazel-tools/tree/master/gorevive) that Atlassian maintains.\n\n### Text Editors\n\n- Support for VSCode via [vscode-go](https://code.visualstudio.com/docs/languages/go#_build-and-diagnose) by changing the `go.lintTool` setting to `revive`:\n\n```json\n{\n  \"go.lintTool\": \"revive\",\n}\n```\n\n- Support for GoLand via [File Watchers](https://dev.to/s0xzwasd/configure-revive-go-linter-in-goland-2ggl).\n- Support for vim via [dense-analysis/ale](https://github.com/dense-analysis/ale).\n\n  ```vim\n  let g:ale_linters = {\n  \\   'go': ['revive'],\n  \\}\n  ```\n\n- Support for Neovim via [null-ls.nvim](https://github.com/jose-elias-alvarez/null-ls.nvim).\n\n  ```lua\n  require(\"null-ls\").setup({\n      sources = {\n          require(\"null-ls\").builtins.diagnostics.revive\n      },\n  })\n  ```\n\n### GitHub Actions\n\n- [Revive Action](https://github.com/marketplace/actions/revive-action) with annotation support\n\n### Continuous Integration\n\n[Codeac.io](https://www.codeac.io?ref=revive) - Automated code review service integrates with GitHub,\nBitbucket and GitLab (even self-hosted) and helps you fight technical debt.\nCheck your [pull-requests](https://www.codeac.io/documentation/pull-requests.html?ref=revive) with\n[revive](https://www.codeac.io/documentation/revive-configuration.html?ref=revive) automatically.\n(Free for open-source projects)\n\n### Linter aggregators\n\n#### golangci-lint\n\nTo enable `revive` in `golangci-lint` you need to add `revive` to the list of enabled linters:\n\n```yaml\n# golangci-lint configuration file\nversion: \"2\"\nlinters:\n   enable:\n     - revive\n```\n\nThen `revive` can be configured by adding an entry to the `linters.settings` section of the configuration, for example:\n\n```yaml\n# golangci-lint configuration file\nlinters:\n  settings:\n    revive:\n      severity: warning\n      rules:\n        - name: atomic\n        - name: line-length-limit\n          severity: error\n          arguments: [80]\n        - name: unhandled-error\n          arguments: [\"fmt.Printf\", \"myFunction\"]\n```\n\nThe above configuration enables three rules of `revive`: _atomic_, _line-length-limit_ and _unhandled-error_ and passes some arguments to the last two.\nThe [Configuration](#configuration) section of this document provides details on how to configure `revive`.\nNote that while `revive` configuration is in TOML, that of `golangci-lint` is in YAML or JSON.\nSee the [golangci-lint website](https://golangci-lint.run/usage/linters/#revive) for more information about configuring `revive`.\n\nPlease notice that if no particular configuration is provided, `revive` will behave as `golint` does, i.e. all `golint` rules are enabled\n(the [Available Rules table](#available-rules) details what are the `golint` rules).\nWhen a configuration is provided, only rules in the configuration are enabled.\n\n### Command Line Flags\n\n`revive` accepts the following command line parameters:\n\n- `-config [PATH]` - path to the config file in TOML format, defaults to `$HOME/revive.toml` if present.\n- `-exclude [PATTERN]` - pattern for files/directories/packages to be excluded for linting.\nYou can specify the files you want to exclude for linting either as package name (i.e. `github.com/mgechev/revive`),\nlist them as individual files (i.e. `file.go`), directories (i.e. `./foo/...`), or any combination of the three.\nIf no exclusion patterns are specified, `vendor/...` will be excluded by default.\n- `-formatter [NAME]` - formatter to be used for the output. The currently available formatters are:\n\n  - `default` - will output the failures the same way that `golint` does.\n  - `json` - outputs the failures in JSON format.\n  - `ndjson` - outputs the failures as a stream in newline delimited JSON (NDJSON) format.\n  - `friendly` - outputs the failures when found. Shows the summary of all the failures.\n  - `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.\n  - `checkstyle` - outputs the failures in XML format compatible with that of Java's [Checkstyle](https://checkstyle.org/).\n- `-max_open_files` -  maximum number of open files at the same time. Defaults to unlimited.\n- `-set_exit_status` - set exit status to 1 if any issues are found, overwrites `errorCode` and `warningCode` in config.\n- `-version` - get revive version.\n\n### Sample Invocations\n\n```shell\nrevive -config revive.toml -exclude file1.go -exclude file2.go -formatter friendly github.com/mgechev/revive package/...\n```\n\n- The command above will use the configuration from `revive.toml`\n- `revive` will ignore `file1.go` and `file2.go`\n- The output will be formatted with the `friendly` formatter\n- The linter will analyze `github.com/mgechev/revive` and the files in `package`\n\n### Comment Directives\n\nUsing comments, you can disable the linter for the entire file or only a range of lines:\n\n```go\n//revive:disable\n\nfunc Public() {}\n\n//revive:enable\n```\n\nThe snippet above, will disable `revive` between the `revive:disable` and `revive:enable` comments.\nIf you skip `revive:enable`, the linter will be disabled for the rest of the file.\n\nWith `revive:disable-next-line` and `revive:disable-line` you can disable `revive` on a particular code line.\n\nYou can do the same on a rule level. In case you want to disable only a particular rule, you can use:\n\n```go\n//revive:disable:unexported-return\nfunc Public() private {\n\treturn private\n}\n\n//revive:enable:unexported-return\n```\n\nThis way, `revive` will not warn you that you're returning an object of an unexported type, from an exported function.\n\nYou can document why you disable the linter by adding a trailing text in the directive, for example\n\n```go\n//revive:disable Until the code is stable\n```\n\n```go\n//revive:disable:cyclomatic High complexity score but easy to understand\n```\n\nYou can also configure `revive` to enforce documenting linter disabling directives by adding\n\n```toml\n[directive.specify-disable-reason]\n```\n\nin the configuration. You can set the severity (defaults to _warning_) of the violation of this directive\n\n```toml\n[directive.specify-disable-reason]\nseverity = \"error\"\n```\n\n### Configuration\n\n`revive` can be configured with a TOML file. Here's a sample configuration with an explanation of the individual properties:\n\n```toml\n# When set to false, ignores files with \"GENERATED\" header, similar to golint\nignoreGeneratedHeader = true\n\n# Sets the default severity to \"warning\"\nseverity = \"warning\"\n\n# Sets the default failure confidence. This means that linting errors\n# with less than 0.8 confidence will be ignored.\nconfidence = 0.8\n\n# Sets the error code for failures with the \"error\" severity\nerrorCode = 0\n\n# Sets the error code for failures with severity \"warning\"\nwarningCode = 0\n\n# Configuration of the `cyclomatic` rule. Here we specify that\n# the rule should fail if it detects code with higher complexity than 10.\n[rule.cyclomatic]\narguments = [10]\n\n# Sets the severity of the `package-comments` rule to \"error\".\n[rule.package-comments]\nseverity = \"error\"\n```\n\nBy default `revive` will enable only the linting rules that are named in the configuration file.\nFor example, the previous configuration file makes `revive` to enable only _cyclomatic_ and _package-comments_ linting rules.\n\nTo enable all available rules you need to add:\n\n```toml\nenableAllRules = true\n```\n\nThis will enable all available rules no matter what rules are named in the configuration file.\n\nTo disable a rule, you simply mark it as disabled in the configuration.\nFor example:\n\n```toml\n[rule.line-length-limit]\nDisabled = true\n```\n\nWhen enabling all rules you still need/can provide specific configurations for rules.\nThe following file is an example configuration where all rules are enabled, except for those that are explicitly disabled,\nand some rules are configured with particular arguments:\n\n```toml\nseverity = \"warning\"\nconfidence = 0.8\nerrorCode = 0\nwarningCode = 0\n\n# Enable all available rules\nenableAllRules = true\n\n# Disabled rules\n[rule.blank-imports]\nDisabled = true\n[rule.file-header]\nDisabled = true\n[rule.max-public-structs]\nDisabled = true\n[rule.line-length-limit]\nDisabled = true\n[rule.function-length]\nDisabled = true\n[rule.banned-characters]\nDisabled = true\n\n# Rule tuning\n[rule.argument-limit]\nArguments = [5]\n[rule.cyclomatic]\nArguments = [10]\n[rule.cognitive-complexity]\nArguments = [7]\n[rule.function-result-limit]\nArguments = [3]\n[rule.error-strings]\nArguments = [\"mypackage.Error\"]\n```\n\n### Default Configuration\n\nThe default configuration of `revive` can be found at `defaults.toml`.\nThis will enable all rules available in `golint` and use their default configuration (i.e. the way they are hardcoded in `golint`).\n\n```shell\nrevive -config defaults.toml github.com/mgechev/revive\n```\n\nThis will use the configuration file `defaults.toml`, the `default` formatter, and will run linting over the `github.com/mgechev/revive` package.\n\n### Custom Configuration\n\n```shell\nrevive -config config.toml -formatter friendly github.com/mgechev/revive\n```\n\nThis will use `config.toml`, the `friendly` formatter, and will run linting over the `github.com/mgechev/revive` package.\n\n### Recommended Configuration\n\nThe following snippet contains the recommended `revive` configuration that you can use in your project:\n\n```toml\nignoreGeneratedHeader = false\nseverity = \"warning\"\nconfidence = 0.8\nerrorCode = 0\nwarningCode = 0\n\n[rule.blank-imports]\n[rule.context-as-argument]\n[rule.context-keys-type]\n[rule.dot-imports]\n[rule.error-return]\n[rule.error-strings]\n[rule.error-naming]\n[rule.exported]\n[rule.increment-decrement]\n[rule.var-naming]\n[rule.var-declaration]\n[rule.package-comments]\n[rule.range]\n[rule.receiver-naming]\n[rule.time-naming]\n[rule.unexported-return]\n[rule.indent-error-flow]\n[rule.errorf]\n[rule.empty-block]\n[rule.superfluous-else]\n[rule.unused-parameter]\n[rule.unreachable-code]\n[rule.redefines-builtin-id]\n```\n\n### Rule-level file excludes\n\nYou also can setup custom excludes for each rule.\n\nIt's an alternative for the global `-exclude` program arg.\n\n```toml\nignoreGeneratedHeader = false\nseverity = \"warning\"\nconfidence = 0.8\nerrorCode = 0\nwarningCode = 0\n\n[rule.blank-imports]\nExclude = [\"**/*.pb.go\"]\n[rule.context-as-argument]\nExclude = [\"src/somepkg/*.go\", \"TEST\"]\n```\n\nYou can use the following exclude patterns\n\n1. full paths to files `src/pkg/mypkg/some.go`\n2. globs `src/**/*.pb.go`\n3. regexes (should have prefix ~) `~\\.(pb|auto|generated)\\.go$`\n4. well-known `TEST` (same as `**/*_test.go`)\n5. special cases:\n  a. `*` and `~` patterns exclude all files (same effect as disabling the rule)\n  b. `\"\"` (empty) pattern excludes nothing\n\n\u003e 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\"\n\n## Available Rules\n\nList of all available rules. The rules ported from `golint` are left unchanged and indicated in the `golint` column.\n\n| Name                  | Config | Description                                                      | `golint` | Typed |\n| --------------------- | :----: | :--------------------------------------------------------------- | :------: | :---: |\n| [`add-constant`](./RULES_DESCRIPTIONS.md#add-constant)        |  map   | Suggests using constant for magic numbers and string literals    |    no    |  no   |\n| [`argument-limit`](./RULES_DESCRIPTIONS.md#argument-limit)      |  int (defaults to 8)  | Specifies the maximum number of arguments a function can receive |    no    |  no   |\n| [`atomic`](./RULES_DESCRIPTIONS.md#atomic)              |  n/a   | Check for common mistaken usages of the `sync/atomic` package    |    no    |  no   |\n| [`banned-characters`](./RULES_DESCRIPTIONS.md#banned-characters)          |  []string (defaults to []string{})   |  Checks banned characters in identifiers |    no    |  no   |\n| [`bare-return`](./RULES_DESCRIPTIONS.md#bare-return) | n/a  | Warns on bare returns   |    no    |  no   |\n| [`blank-imports`](./RULES_DESCRIPTIONS.md#blank-imports)       |  n/a   | Disallows blank imports                                          |   yes    |  no   |\n| [`bool-literal-in-expr`](./RULES_DESCRIPTIONS.md#bool-literal-in-expr)|  n/a   | Suggests removing Boolean literals from logic expressions        |    no    |  no   |\n| [`call-to-gc`](./RULES_DESCRIPTIONS.md#call-to-gc)   | n/a    | Warns on explicit call to the garbage collector    |    no    |  no   |\n| [`cognitive-complexity`](./RULES_DESCRIPTIONS.md#cognitive-complexity)          |  int (defaults to 7) | Sets restriction for maximum Cognitive complexity.              |    no    |  no   |\n| [`comment-spacings`](./RULES_DESCRIPTIONS.md#comment-spacings)          |  []string   |  Warns on malformed comments |    no    |  no   |\n| [`comments-density`](./RULES_DESCRIPTIONS.md#comments-density) |  int (defaults to 0)  | Enforces a minimum comment / code relation |    no    |  no   |\n| [`confusing-naming`](./RULES_DESCRIPTIONS.md#confusing-naming)    |  n/a   | Warns on methods with names that differ only by capitalization   |    no    |  no   |\n| [`confusing-results`](./RULES_DESCRIPTIONS.md#confusing-results)   |  n/a   | Suggests to name potentially confusing function results          |    no    |  no   |\n| [`constant-logical-expr`](./RULES_DESCRIPTIONS.md#constant-logical-expr)   |  n/a   | Warns on constant logical expressions                        |    no    |  no   |\n| [`context-as-argument`](./RULES_DESCRIPTIONS.md#context-as-argument) |  n/a   | `context.Context` should be the first argument of a function.    |   yes    |  no   |\n| [`context-keys-type`](./RULES_DESCRIPTIONS.md#context-key-types)   |  n/a   | Disallows the usage of basic types in `context.WithValue`.       |   yes    |  yes  |\n| [`cyclomatic`](./RULES_DESCRIPTIONS.md#cyclomatic)          |  int (defaults to 10)   | Sets restriction for maximum Cyclomatic complexity.              |    no    |  no   |\n| [`datarace`](./RULES_DESCRIPTIONS.md#datarace)          |  n/a   |  Spots potential dataraces |    no    |  no   |\n| [`deep-exit`](./RULES_DESCRIPTIONS.md#deep-exit)           |  n/a   | Looks for program exits in funcs other than `main()` or `init()` |    no    |  no   |\n| [`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   |\n| [`dot-imports`](./RULES_DESCRIPTIONS.md#dot-imports)         |  n/a   | Forbids `.` imports.                                             |   yes    |  no   |\n| [`duplicated-imports`](./RULES_DESCRIPTIONS.md#duplicated-imports) | n/a  | Looks for packages that are imported two or more times   |    no    |  no   |\n| [`early-return`](./RULES_DESCRIPTIONS.md#early-return)          | []string   | Spots if-then-else statements where the predicate may be inverted to reduce nesting |    no    |  no   |\n| [`empty-block`](./RULES_DESCRIPTIONS.md#empty-block)         |  n/a   | Warns on empty code blocks                                       |    no    |  yes   |\n| [`empty-lines`](./RULES_DESCRIPTIONS.md#empty-lines)   | n/a | Warns when there are heading or trailing newlines in a block              |    no    |  no   |\n| [`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   |\n| [`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   |\n| [`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   |\n| [`enforce-switch-style`](./RULES_DESCRIPTIONS.md#enforce-switch-style) |  []string (defaults to enforce occurrence and position) |  Enforces consistent usage of `default` on `switch` statements. |    no    |  no   |\n| [`error-naming`](./RULES_DESCRIPTIONS.md#error-naming)        |  n/a   | Naming of error variables.                                       |   yes    |  no   |\n| [`error-return`](./RULES_DESCRIPTIONS.md#error-return)        |  n/a   | The error return parameter should be last.                       |   yes    |  no   |\n| [`error-strings`](./RULES_DESCRIPTIONS.md#error-strings)       |  []string   | Conventions around error strings.                                |   yes    |  no   |\n| [`errorf`](./RULES_DESCRIPTIONS.md#errorf)              |  n/a   | Should replace `errors.New(fmt.Sprintf())` with `fmt.Errorf()`   |   yes    |  yes  |\n| [`exported`](./RULES_DESCRIPTIONS.md#exported)            |  []string   | Naming and commenting conventions on exported symbols.           |   yes    |  no   |\n| [`file-header`](./RULES_DESCRIPTIONS.md#file-header)         | string (defaults to none)| Header which each file should have.                              |    no    |  no   |\n| [`file-length-limit`](./RULES_DESCRIPTIONS.md#file-length-limit) | map (optional)| Enforces a maximum number of lines per file |    no    |  no   |\n| [`filename-format`](./RULES_DESCRIPTIONS.md#filename-format) | regular expression (optional) | Enforces the formatting of filenames |   no    |  no   |\n| [`flag-parameter`](./RULES_DESCRIPTIONS.md#flag-parameter)      |  n/a   | Warns on boolean parameters that create a control coupling       |    no    |  no   |\n| [`forbidden-call-in-wg-go`](./RULES_DESCRIPTIONS.md#forbidden-call-in-wg-go)  |  n/a   | Warns on forbidden calls inside calls to wg.Go |    no    |  no   |\n| [`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   |\n| [`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   |\n| [`get-return`](./RULES_DESCRIPTIONS.md#get-return)          |  n/a   | Warns on getters that do not yield any result                    |    no    |  no   |\n| [`identical-branches`](./RULES_DESCRIPTIONS.md#identical-branches)          |  n/a   | Spots if-then-else statements with identical `then` and `else` branches       |    no    |  no   |\n| [`identical-ifelseif-branches`](./RULES_DESCRIPTIONS.md#identical-ifelseif-branches)          |  n/a   | Spots `if ... else if` chains with identical branches.       |    no    |  no   |\n| [`identical-ifelseif-conditions`](./RULES_DESCRIPTIONS.md#identical-ifelseif-conditions)          |  n/a   | Spots identical conditions in  `if ... else if` chains.       |    no    |  no   |\n| [`identical-switch-branches`](./RULES_DESCRIPTIONS.md#identical-switch-branches)          |  n/a   | Spots `switch` with identical branches.       |    no    |  no   |\n| [`identical-switch-conditions`](./RULES_DESCRIPTIONS.md#identical-switch-conditions)          |  n/a   | Spots identical conditions in case clauses of `switch` statements.       |    no    |  no   |\n| [`if-return`](./RULES_DESCRIPTIONS.md#if-return)           |  n/a   | Redundant if when returning an error.                            |   no    |  no   |\n| [`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   |\n| [`import-shadowing`](./RULES_DESCRIPTIONS.md#import-shadowing)   | n/a    | Spots identifiers that shadow an import    |    no    |  no   |\n| [`imports-blocklist`](./RULES_DESCRIPTIONS.md#imports-blocklist)   | []string | Disallows importing the specified packages                     |    no    |  no   |\n| [`increment-decrement`](./RULES_DESCRIPTIONS.md#increment-decrement) |  n/a   | Use `i++` and `i--` instead of `i += 1` and `i -= 1`.            |   yes    |  no   |\n| [`indent-error-flow`](./RULES_DESCRIPTIONS.md#indent-error-flow)   |  []string   | Prevents redundant else statements.                              |   yes    |  no   |\n| [`inefficient-map-lookup`](./RULES_DESCRIPTIONS.md#inefficient-map-lookup)   |  n/a  | Spots iterative searches for a key in a map           |   no    |  yes   |\n| [`line-length-limit`](./RULES_DESCRIPTIONS.md#line-length-limit)   | int (defaults to 80) | Specifies the maximum number of characters in a line             |    no    |  no   |\n| [`max-control-nesting`](./RULES_DESCRIPTIONS.md#max-control-nesting) |  int (defaults to 5)  | Sets restriction for maximum nesting of control structures. |    no    |  no   |\n| [`max-public-structs`](./RULES_DESCRIPTIONS.md#max-public-structs)  |  int (defaults to 5)  | The maximum number of public structs in a file.                  |    no    |  no   |\n| [`modifies-parameter`](./RULES_DESCRIPTIONS.md#modifies-parameter)  |  n/a   | Warns on assignments to function parameters                      |    no    |  no   |\n| [`modifies-value-receiver`](./RULES_DESCRIPTIONS.md#modifies-value-receiver) |  n/a   | Warns on assignments to value-passed method receivers        |    no    |  yes  |\n| [`nested-structs`](./RULES_DESCRIPTIONS.md#nested-structs)          |  n/a   |  Warns on structs within structs |    no    |  no   |\n| [`optimize-operands-order`](./RULES_DESCRIPTIONS.md#optimize-operands-order)          |  n/a   |  Checks inefficient conditional expressions |    no    |  no   |\n| [`package-comments`](./RULES_DESCRIPTIONS.md#package-comments)    |  n/a   | Package commenting conventions.                                  |   yes    |  no   |\n| [`package-directory-mismatch`](./RULES_DESCRIPTIONS.md#package-directory-mismatch)    | string | Checks that package name matches containing directory name     |   no    |  no   |\n| [`range-val-address`](./RULES_DESCRIPTIONS.md#range-val-address)|  n/a   | Warns if address of range value is used dangerously |    no    |  yes   |\n| [`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   |\n| [`range`](./RULES_DESCRIPTIONS.md#range)               |  n/a   | Prevents redundant variables when iterating over a collection.   |   yes    |  no   |\n| [`receiver-naming`](./RULES_DESCRIPTIONS.md#receiver-naming)     |  map (optional)   | Conventions around the naming of receivers.                      |   yes    |  no   |\n| [`redefines-builtin-id`](./RULES_DESCRIPTIONS.md#redefines-builtin-id)|  n/a   | Warns on redefinitions of builtin identifiers                    |    no    |  no   |\n| [`redundant-build-tag`](./RULES_DESCRIPTIONS.md#redundant-build-tag) | n/a   | Warns about redundant `// +build` comment lines |   no    |  no   |\n| [`redundant-import-alias`](./RULES_DESCRIPTIONS.md#redundant-import-alias)          |  n/a   |  Warns on import aliases matching the imported package name |    no    |  no   |\n| [`redundant-test-main-exit`](./RULES_DESCRIPTIONS.md#redundant-test-main-exit) |  n/a   | Suggests removing `Exit` call in `TestMain` function for test files |    no    |  no   |\n| [`string-format`](./RULES_DESCRIPTIONS.md#string-format)          |  map   | Warns on specific string literals that fail one or more user-configured regular expressions            |    no    |  no   |\n| [`string-of-int`](./RULES_DESCRIPTIONS.md#string-of-int)          |  n/a   | Warns on suspicious casts from int to string            |    no    |  yes   |\n| [`struct-tag`](./RULES_DESCRIPTIONS.md#struct-tag)          |  []string   | Checks common struct tags like `json`, `xml`, `yaml`               |    no    |  no   |\n| [`superfluous-else`](./RULES_DESCRIPTIONS.md#superfluous-else)    |  []string   | Prevents redundant else statements (extends [`indent-error-flow`](./RULES_DESCRIPTIONS.md#indent-error-flow)) |    no    |  no   |\n| [`time-date`](./RULES_DESCRIPTIONS.md#time-date)         |  n/a   | Reports bad usage of `time.Date`.                 |   no    |  yes  |\n| [`time-equal`](./RULES_DESCRIPTIONS.md#time-equal)         |  n/a   | Suggests to use `time.Time.Equal` instead of `==` and `!=` for equality check time.                 |   no    |  yes  |\n| [`time-naming`](./RULES_DESCRIPTIONS.md#time-naming)         |  n/a   | Conventions around the naming of time variables.                 |   yes    |  yes  |\n| [`unchecked-type-assertions`](./RULES_DESCRIPTIONS.md#unchecked-type-assertions)         |  n/a   | Disallows type assertions without checking the result.                 |   no    |  yes  |\n| [`unconditional-recursion`](./RULES_DESCRIPTIONS.md#unconditional-recursion)          |  n/a   | Warns on function calls that will lead to (direct) infinite recursion |    no    |  no   |\n| [`unexported-naming`](./RULES_DESCRIPTIONS.md#unexported-naming)          |  n/a   |  Warns on wrongly named un-exported symbols       |    no    |  no   |\n| [`unexported-return`](./RULES_DESCRIPTIONS.md#unexported-return)   |  n/a   | Warns when a public return is from unexported type.              |   yes    |  yes  |\n| [`unhandled-error`](./RULES_DESCRIPTIONS.md#unhandled-error)   | []string   | Warns on unhandled errors returned by function calls    |    no    |  yes   |\n| [`unnecessary-format`](./RULES_DESCRIPTIONS.md#unnecessary-format)    |  n/a   | Identifies calls to formatting functions where the format string does not contain any formatting verbs          |    no    |  no   |\n| [`unnecessary-stmt`](./RULES_DESCRIPTIONS.md#unnecessary-stmt)    |  n/a   | Suggests removing or simplifying unnecessary statements          |    no    |  no   |\n| [`unreachable-code`](./RULES_DESCRIPTIONS.md#unreachable-code)    |  n/a   | Warns on unreachable code                                        |    no    |  no   |\n| [`unsecure-url-scheme`](./RULES_DESCRIPTIONS.md#unsecure-url-scheme)          |  n/a   |  Checks for usage of potentially unsecure URL schemes. |    no    |  no   |\n| [`unused-parameter`](./RULES_DESCRIPTIONS.md#unused-parameter)    |  n/a   | Suggests to rename or remove unused function parameters          |    no    |  no   |\n| [`unused-receiver`](./RULES_DESCRIPTIONS.md#unused-receiver)   | n/a    | Suggests to rename or remove unused method receivers    |    no    |  no   |\n| [`use-any`](./RULES_DESCRIPTIONS.md#use-any)          |  n/a   |  Proposes to replace `interface{}` with its alias `any` |    no    |  no   |\n| [`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   |\n| [`use-fmt-print`](./RULES_DESCRIPTIONS.md#use-fmt-print) | n/a   | Proposes to replace calls to built-in `print` and `println` with their equivalents from `fmt`. |   no    |  no   |\n| [`use-waitgroup-go`](./RULES_DESCRIPTIONS.md#use-waitgroup-go)          |  n/a   |  Proposes to replace `wg.Add ... go {... wg.Done ...}` idiom with `wg.Go` |    no    |  no   |\n| [`useless-break`](./RULES_DESCRIPTIONS.md#useless-break)          |  n/a   |  Warns on useless `break` statements in case clauses |    no    |  no   |\n| [`useless-fallthrough`](./RULES_DESCRIPTIONS.md#useless-fallthrough)  |  n/a   |  Warns on useless `fallthrough` statements in case clauses |    no    |  no   |\n| [`var-declaration`](./RULES_DESCRIPTIONS.md#var-declaration)     |  n/a   | Reduces redundancies around variable declaration.                |   yes    |  yes  |\n| [`var-naming`](./RULES_DESCRIPTIONS.md#var-naming)          |  allowlist \u0026 blocklist of initialisms   | Naming rules.                                                    |   yes    |  no   |\n| [`waitgroup-by-value`](./RULES_DESCRIPTIONS.md#waitgroup-by-value)  |  n/a   | Warns on functions taking sync.WaitGroup as a by-value parameter |    no    |  no   |\n\n## Configurable rules\n\nHere you can find how you can configure some existing rules:\n\n### `var-naming`\n\nThis rule accepts two slices of strings, an allowlist and a blocklist of initialisms. By default, the rule behaves exactly as the alternative\nin `golint` but optionally, you can relax it (see [golint/lint/issues/89](https://github.com/golang/lint/issues/89))\n\n```toml\n[rule.var-naming]\narguments = [[\"ID\"], [\"VM\"]]\n```\n\nThis way, revive will not warn for an identifier called `customId` but will warn that `customVm` should be called `customVM`.\n\n## Available Formatters\n\nThis section lists all the available formatters and provides a screenshot for each one.\n\n### Friendly\n\n![Friendly formatter](/assets/formatter-friendly.png)\n\n### Stylish\n\n![Stylish formatter](/assets/formatter-stylish.png)\n\n### Default\n\nThe default formatter produces the same output as `golint`.\n\n![Default formatter](/assets/formatter-default.png)\n\n### Plain\n\nThe plain formatter produces the same output as the default formatter and appends the URL to the rule description.\n\n![Plain formatter](/assets/formatter-plain.png)\n\n### Unix\n\nThe unix formatter produces the same output as the default formatter but surrounds the rules in `[]`.\n\n![Unix formatter](/assets/formatter-unix.png)\n\n### JSON\n\nThe `json` formatter produces output in JSON format.\n\n### NDJSON\n\nThe `ndjson` formatter produces output in [`Newline Delimited JSON`](https://github.com/ndjson/ndjson-spec) format.\n\n### Checkstyle\n\nThe `checkstyle` formatter produces output in a [Checkstyle-like](https://checkstyle.sourceforge.io/) format.\n\n### SARIF\n\nThe `sarif`  formatter produces output in SARIF, for _Static Analysis Results Interchange Format_,\na standard JSON-based format for the output of static analysis tools defined and promoted by [OASIS](https://www.oasis-open.org/).\n\nCurrent 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\n).\n\n## Extensibility\n\nThe tool can be extended with custom rules or formatters. This section contains additional information on how to implement such.\n\nTo extend the linter with a custom rule you can push it to this repository or use `revive` as a library (see below)\n\nTo add a custom formatter you'll have to push it to this repository or fork it.\nThis is due to the limited `-buildmode=plugin` support which [works only on Linux (with known issues)](https://golang.org/pkg/plugin/).\n\n### Writing a Custom Rule\n\nSee [DEVELOPING.md](./DEVELOPING.md) for instructions on how to write a custom rule.\n\n#### Using `revive` as a library\n\nIf a rule is specific to your use case\n(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.\n\nThe following code shows how to use `revive` in your application.\nIn the example only one rule is added (`myRule`), of course, you can add as many as you need to.\nYour rules can be configured programmatically or with the standard `revive` configuration file.\nThe full rule set of `revive` is also actionable by your application.\n\n```go\npackage main\n\nimport (\n\t\"github.com/mgechev/revive/cli\"\n\t\"github.com/mgechev/revive/lint\"\n\t\"github.com/mgechev/revive/revivelib\"\n)\n\nfunc main() {\n\tcli.RunRevive(revivelib.NewExtraRule(\u0026myRule{}, lint.RuleConfig{}))\n}\n\ntype myRule struct{}\n\nfunc (f myRule) Name() string {\n\treturn \"myRule\"\n}\n\nfunc (f myRule) Apply(*lint.File, lint.Arguments) []lint.Failure {\n\t// ...\n}\n```\n\nYou can still go further and use `revive` without its CLI, as part of your library, or your CLI:\n\n```go\npackage mylib\n\nimport (\n\t\"github.com/mgechev/revive/config\"\n\t\"github.com/mgechev/revive/lint\"\n\t\"github.com/mgechev/revive/revivelib\"\n)\n\n// Error checking removed for clarity\nfunc LintMyFile(file string) {\n\tconf, _ := config.GetConfig(\"../defaults.toml\")\n\n\trevive, _ := revivelib.New(\n\t\tconf, // Configuration file\n\t\ttrue, // Set exit status\n\t\t2048, // Max open files\n\n\t\t// Then add as many extra rules as you need\n\t\trevivelib.NewExtraRule(\u0026myRule{}, lint.RuleConfig{}),\n\t)\n\n\tfailuresChan, err := revive.Lint(\n\t\trevivelib.Include(file),\n\t\trevivelib.Exclude(\"./fixtures\"),\n\t\t// You can use as many revivelib.Include or revivelib.Exclude as required\n\t)\n\tif err != nil {\n\t\tpanic(\"Shouldn't have failed: \" + err.Error())\n\t}\n\n\t// Now let's return the formatted errors\n\tfailures, exitCode, _ := revive.Format(\"stylish\", failuresChan)\n\n\t// failures is the string with all formatted lint error messages\n\t// exit code is 0 if no errors, 1 if errors (unless config options change it)\n\t// ... do something with them\n}\n\ntype myRule struct{}\n\nfunc (f myRule) Name() string {\n\treturn \"myRule\"\n}\n\nfunc (f myRule) Apply(*lint.File, lint.Arguments) []lint.Failure {\n\t// ...\n}\n```\n\n### Custom Formatter\n\nEach formatter needs to implement the following interface:\n\n```go\ntype Formatter interface {\n\tFormat(\u003c-chan Failure, Config) (string, error)\n\tName() string\n}\n```\n\nThe `Format` method accepts a channel of `Failure` instances and the configuration of the enabled rules.\nThe `Name()` method should return a string different from the names of the already existing rules.\nThis string is used when specifying the formatter when invoking the `revive` CLI tool.\n\nFor a sample formatter, take a look at [this file](/formatter/json.go).\n\n## Speed Comparison\n\nCompared to `golint`, `revive` performs better because it lints the files for each individual rule into a separate goroutine.\nHere's a basic performance benchmark on MacBook Pro Early 2013 run on Kubernetes:\n\n### golint\n\n```shellsession\n$ time golint kubernetes/... \u003e /dev/null\n\nreal    0m54.837s\nuser    0m57.844s\nsys     0m9.146s\n```\n\n### revive's speed\n\n```shellsession\n# no type checking\n$ time revive -config untyped.toml kubernetes/... \u003e /dev/null\n\nreal    0m8.471s\nuser    0m40.721s\nsys     0m3.262s\n```\n\nKeep in mind that if you use rules that require type checking, the performance may drop to 2x faster than `golint`:\n\n```shellsession\n# type checking enabled\n$ time revive kubernetes/... \u003e /dev/null\n\nreal    0m26.211s\nuser    2m6.708s\nsys     0m17.192s\n```\n\nCurrently, type-checking is enabled by default. If you want to run the linter without type-checking, remove all typed rules from the configuration file.\n\n## Overriding colorization detection\n\nBy default, `revive` determines whether or not to colorize its output based on whether it's connected to a TTY or not.\nThis works for most use cases, but may not behave as expected if you use `revive` in a pipeline of commands,\nwhere STDOUT is being piped to another command.\n\nTo force colorization, add `REVIVE_FORCE_COLOR=1` to the environment you're running in. For example:\n\n```shell\nREVIVE_FORCE_COLOR=1 revive -formatter friendly ./... | tee revive.log\n```\n\n## Who uses Revive\n\n\u003c!-- markdownlint-disable MD013 --\u003e\n\n- [`tidb`](https://github.com/pingcap/tidb) - TiDB is a distributed HTAP database compatible with the MySQL protocol\n- [`grafana`](https://github.com/grafana/grafana) - The tool for beautiful monitoring and metric analytics \u0026 dashboards for Graphite, InfluxDB \u0026 Prometheus \u0026 More\n- [`etcd`](https://github.com/etcd-io/etcd) - Distributed reliable key-value store for the most critical data of a distributed system\n- [`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\n- [`ferret`](https://github.com/MontFerret/ferret) - Declarative web scraping\n- [`gopass`](https://github.com/gopasspw/gopass) - The slightly more awesome standard unix password manager for teams\n- [`gitea`](https://github.com/go-gitea/gitea) - Git with a cup of tea, painless self-hosted git service\n- [`excelize`](https://github.com/360EntSecGroup-Skylar/excelize) - Go library for reading and writing Microsoft Excel™ (XLSX) files\n- [`aurora`](https://github.com/xuri/aurora) - aurora is a web-based Beanstalk queue server console written in Go\n- [`soar`](https://github.com/XiaoMi/soar) - SQL Optimizer And Rewriter\n- [`pyroscope`](https://github.com/pyroscope-io/pyroscope) - Continuous profiling platform\n- [`gorush`](https://github.com/appleboy/gorush) - A push notification server written in Go (Golang).\n- [`dry`](https://github.com/moncho/dry) - dry - A Docker manager for the terminal.\n- [`go-echarts`](https://github.com/chenjiandongx/go-echarts) - The adorable charts library for Golang\n- [`reviewdog`](https://github.com/reviewdog/reviewdog) - Automated code review tool integrated with any code analysis tools regardless of programming language\n- [`rudder-server`](https://github.com/rudderlabs/rudder-server) - Privacy and Security focused Segment-alternative, in Golang and React.\n- [`sklearn`](https://github.com/pa-m/sklearn) - A partial port of scikit-learn written in Go.\n- [`protoc-gen-doc`](https://github.com/pseudomuto/protoc-gen-doc) - Documentation generator plugin for Google Protocol Buffers.\n- [`llvm`](https://github.com/llir/llvm) - Library for interacting with LLVM IR in pure Go.\n- [`jenkins-library`](https://github.com/SAP/jenkins-library) - Jenkins shared library for Continuous Delivery pipelines by SAP.\n- [`pd`](https://github.com/tikv/pd) - Placement driver for TiKV.\n- [`shellhub`](https://github.com/shellhub-io/shellhub) - ShellHub enables teams to easily access any Linux device behind firewall and NAT.\n- [`lorawan-stack`](https://github.com/TheThingsNetwork/lorawan-stack) - The Things Network Stack for LoRaWAN V3\n- [`gin-jwt`](https://github.com/appleboy/gin-jwt) - This is a JWT middleware for Gin framework.\n- [`gofight`](https://github.com/appleboy/gofight) - Testing API Handler written in Golang.\n- [`Beaver`](https://github.com/Clivern/Beaver) - A Real Time Messaging Server.\n- [`ggz`](https://github.com/go-ggz/ggz) - An URL shortener service written in Golang\n- [`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.\n- [`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.\n- [`checker`](https://github.com/cinar/checker) - Checker helps validating user input through rules defined in struct tags or directly through functions.\n- [`milvus`](https://github.com/milvus-io/milvus) - A cloud-native vector database, storage for next generation AI applications.\n- [`indicator`](https://github.com/cinar/indicator) - Indicator provides various technical analysis indicators, strategies, and a backtesting framework.\n\n\u003c!-- markdownlint-enable MD013 --\u003e\n\n_Open a PR to add your project_.\n\n## Contributors\n\n### Maintainers\n\n[\u003cimg alt=\"mgechev\" src=\"https://avatars.githubusercontent.com/u/455023?v=4\u0026s=100\" width=\"100\"\u003e](https://github.com/mgechev) |[\u003cimg alt=\"chavacava\" src=\"https://avatars.githubusercontent.com/u/25788468?v=4\u0026s=100\" width=\"100\"\u003e](https://github.com/chavacava) |[\u003cimg alt=\"denisvmedia\" src=\"https://avatars.githubusercontent.com/u/5462781?v=4\u0026s=100\" width=\"100\"\u003e](https://github.com/denisvmedia) |[\u003cimg alt=\"alexandear\" src=\"https://avatars.githubusercontent.com/u/3228886?v=4\u0026s=100\" width=\"100\"\u003e](https://github.com/alexandear) |\n:---: |:---: |:---: |:---: |\n[mgechev](https://github.com/mgechev) |[chavacava](https://github.com/chavacava) |[denisvmedia](https://github.com/denisvmedia) |[alexandear](https://github.com/alexandear) |\n\n### All\n\nThis project exists thanks to all the people who contribute.\n\n\u003ca href=\"https://github.com/mgechev/revive/graphs/contributors\"\u003e\n  \u003cimg alt=\"All Contributors\" src=\"https://contrib.rocks/image?repo=mgechev/revive\u0026max=500\" /\u003e\n\u003c/a\u003e\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgechev%2Frevive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmgechev%2Frevive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgechev%2Frevive/lists"}