1
0
mirror of https://github.com/mgechev/revive.git synced 2024-11-21 17:16:40 +02:00

adds filename-format rule (#1092)

This commit is contained in:
chavacava 2024-11-02 14:23:46 -03:00 committed by GitHub
parent 511e4e65ff
commit eb18252088
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 125 additions and 0 deletions

View File

@ -548,6 +548,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
| [`max-control-nesting`](./RULES_DESCRIPTIONS.md#max-control-nesting) | int (defaults to 5) | Sets restriction for maximum nesting of control structures. | no | no |
| [`comments-density`](./RULES_DESCRIPTIONS.md#comments-density) | int (defaults to 0) | Enforces a minimum comment / code relation | no | no |
| [`file-length-limit`](./RULES_DESCRIPTIONS.md#file-length-limit) | map (optional)| Enforces a maximum number of lines per file | no | no |
| [`filename-format`](./RULES_DESCRIPTIONS.md#filename-format) | regular expression (optional) | Enforces the formatting of filenames | no | no |
## Configurable rules

View File

@ -39,6 +39,7 @@ List of all available rules.
- [exported](#exported)
- [file-header](#file-header)
- [file-length-limit](#file-length-limit)
- [filename-format](#filename-format)
- [flag-parameter](#flag-parameter)
- [function-length](#function-length)
- [function-result-limit](#function-result-limit)
@ -519,6 +520,18 @@ Example:
arguments = [{max=100,skipComments=true,skipBlankLines=true}]
```
## filename-format
_Description_: enforces conventions on source file names. By default, the rule enforces filenames of the form `^[_A-Za-z0-9][_A-Za-z0-9-]*.go$`: Optionally, the rule can be configured to enforce other forms.
_Configuration_: (string) regular expression for source filenames.
Example:
```toml
[rule.filename-format]
arguments=["^[_a-z][_a-z0-9]*.go$"]
```
## flag-parameter
_Description_: If a function controls the flow of another by passing it information on what to do, both functions are said to be [control-coupled](https://en.wikipedia.org/wiki/Coupling_(computer_programming)#Procedural_programming).

View File

@ -97,6 +97,7 @@ var allRules = append([]lint.Rule{
&rule.MaxControlNestingRule{},
&rule.CommentsDensityRule{},
&rule.FileLengthLimitRule{},
&rule.FilenameFormatRule{},
}, defaultRules...)
var allFormatters = []lint.Formatter{

87
rule/filename-format.go Normal file
View File

@ -0,0 +1,87 @@
package rule
import (
"fmt"
"path/filepath"
"regexp"
"sync"
"unicode"
"github.com/mgechev/revive/lint"
)
// FilenameFormatRule lints source filenames according to a set of regular expressions given as arguments
type FilenameFormatRule struct {
format *regexp.Regexp
sync.Mutex
}
// Apply applies the rule to the given file.
func (r *FilenameFormatRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
r.configure(arguments)
filename := filepath.Base(file.Name)
if r.format.MatchString(filename) {
return nil
}
failureMsg := fmt.Sprintf("Filename %s is not of the format %s.%s", filename, r.format.String(), r.getMsgForNonAsciiChars(filename))
return []lint.Failure{{
Confidence: 1,
Failure: failureMsg,
RuleName: r.Name(),
Node: file.AST.Name,
}}
}
func (r *FilenameFormatRule) getMsgForNonAsciiChars(str string) string {
result := ""
for _, c := range str {
if c <= unicode.MaxASCII {
continue
}
result += fmt.Sprintf(" Non ASCII character %c (%U) found.", c, c)
}
return result
}
// Name returns the rule name.
func (*FilenameFormatRule) Name() string {
return "filename-format"
}
var defaultFormat = regexp.MustCompile("^[_A-Za-z0-9][_A-Za-z0-9-]*.go$")
func (r *FilenameFormatRule) configure(arguments lint.Arguments) {
r.Lock()
defer r.Unlock()
if r.format != nil {
return
}
argsCount := len(arguments)
if argsCount == 0 {
r.format = defaultFormat
return
}
if argsCount > 1 {
panic(fmt.Sprintf("rule %q expects only one argument, got %d %v", r.Name(), argsCount, arguments))
}
arg := arguments[0]
str, ok := arg.(string)
if !ok {
panic(fmt.Sprintf("rule %q expects a string argument, got %v of type %T", r.Name(), arg, arg))
}
format, err := regexp.Compile(str)
if err != nil {
panic(fmt.Sprintf("rule %q expects a valid regexp argument, got %v for %s", r.Name(), err, arg))
}
r.format = format
}

View File

@ -0,0 +1,16 @@
package test
import (
"testing"
"github.com/mgechev/revive/lint"
"github.com/mgechev/revive/rule"
)
func TestLintFilenameFormat(t *testing.T) {
testRule(t, "filename-ok-default", &rule.FilenameFormatRule{}, &lint.RuleConfig{})
testRule(t, "filenamе-with-non-ascii-char", &rule.FilenameFormatRule{}, &lint.RuleConfig{})
testRule(t, "filename_with_underscores", &rule.FilenameFormatRule{}, &lint.RuleConfig{Arguments: []any{"^[A-Za-z][A-Za-z0-9]*.go$"}})
}

1
testdata/filename-ok-default.go vendored Normal file
View File

@ -0,0 +1 @@
package main

3
testdata/filename_with_underscores.go vendored Normal file
View File

@ -0,0 +1,3 @@
package main
// MATCH:1 /Filename filename_with_underscores.go is not of the format ^[A-Za-z][A-Za-z0-9]*.go$./

View File

@ -0,0 +1,3 @@
package main
// MATCH:1 /Filename filenamе-with-non-ascii-char.go is not of the format ^[_A-Za-z0-9][_A-Za-z0-9-]*.go$. Non ASCII character е (U+0435) found./