Skip to content

Commit f900b6c

Browse files
authored
feat: add support for import-alias-naming rule (#881)
1 parent 0357df7 commit f900b6c

File tree

7 files changed

+145
-0
lines changed

7 files changed

+145
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ List of all available rules. The rules ported from `golint` are left unchanged a
533533
| [`datarace`](./RULES_DESCRIPTIONS.md#datarace) | n/a | Spots potential dataraces | no | no |
534534
| [`comment-spacings`](./RULES_DESCRIPTIONS.md#comment-spacings) | []string | Warns on malformed comments | no | no |
535535
| [`redundant-import-alias`](./RULES_DESCRIPTIONS.md#redundant-import-alias) | n/a | Warns on import aliases matching the imported package name | no | no |
536+
| [`import-alias-naming`](./RULES_DESCRIPTIONS.md#import-alias-naming) | string (defaults to ^[a-z][a-z0-9]{0,}$) | Conventions around the naming of import aliases. | no | no |
536537

537538

538539
## Configurable rules

RULES_DESCRIPTIONS.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ List of all available rules.
4444
- [indent-error-flow](#indent-error-flow)
4545
- [imports-blacklist](#imports-blacklist)
4646
- [import-shadowing](#import-shadowing)
47+
- [import-alias-naming](#import-alias-naming)
4748
- [line-length-limit](#line-length-limit)
4849
- [max-public-structs](#max-public-structs)
4950
- [modifies-parameter](#modifies-parameter)
@@ -489,6 +490,22 @@ name of an imported package. This rule spots identifiers that shadow an import.
489490

490491
_Configuration_: N/A
491492

493+
## import-alias-naming
494+
495+
_Description_: Aligns with Go's naming conventions, as outlined in the official
496+
[blog post](https://go.dev/blog/package-names). It enforces clear and lowercase import alias names, echoing
497+
the principles of good package naming. Users can follow these guidelines by default or define a custom regex rule.
498+
Importantly, aliases with underscores ("_") are always allowed.
499+
500+
_Configuration_: (string) regular expression to match the aliases (default: ^[a-z][a-z0-9]{0,}$)
501+
502+
Example:
503+
504+
```toml
505+
[rule.import-alias-naming]
506+
arguments =["^[a-z][a-z0-9]{0,}$"]
507+
```
508+
492509
## line-length-limit
493510

494511
_Description_: Warns in the presence of code lines longer than a configured maximum.

config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ var allRules = append([]lint.Rule{
8888
&rule.CommentSpacingsRule{},
8989
&rule.IfReturnRule{},
9090
&rule.RedundantImportAlias{},
91+
&rule.ImportAliasNamingRule{},
9192
}, defaultRules...)
9293

9394
var allFormatters = []lint.Formatter{

rule/import-alias-naming.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package rule
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"sync"
7+
8+
"github.com/mgechev/revive/lint"
9+
)
10+
11+
// ImportAliasNamingRule lints import alias naming.
12+
type ImportAliasNamingRule struct {
13+
configured bool
14+
namingRuleRegexp *regexp.Regexp
15+
sync.Mutex
16+
}
17+
18+
const defaultNamingRule = "^[a-z][a-z0-9]{0,}$"
19+
20+
var defaultNamingRuleRegexp = regexp.MustCompile(defaultNamingRule)
21+
22+
func (r *ImportAliasNamingRule) configure(arguments lint.Arguments) {
23+
r.Lock()
24+
defer r.Unlock()
25+
if r.configured {
26+
return
27+
}
28+
29+
if len(arguments) < 1 {
30+
r.namingRuleRegexp = defaultNamingRuleRegexp
31+
return
32+
}
33+
34+
namingRule, ok := arguments[0].(string) // Alt. non panicking version
35+
if !ok {
36+
panic(fmt.Sprintf("Invalid argument '%v' for 'import-alias-naming' rule. Expecting string, got %T", arguments[0], arguments[0]))
37+
}
38+
39+
var err error
40+
r.namingRuleRegexp, err = regexp.Compile(namingRule)
41+
if err != nil {
42+
panic(fmt.Sprintf("Invalid argument to the import-alias-naming rule. Expecting %q to be a valid regular expression, got: %v", namingRule, err))
43+
}
44+
}
45+
46+
// Apply applies the rule to given file.
47+
func (r *ImportAliasNamingRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure {
48+
r.configure(arguments)
49+
50+
var failures []lint.Failure
51+
52+
for _, is := range file.AST.Imports {
53+
path := is.Path
54+
if path == nil {
55+
continue
56+
}
57+
58+
alias := is.Name
59+
if alias == nil || alias.Name == "_" {
60+
continue
61+
}
62+
63+
if !r.namingRuleRegexp.MatchString(alias.Name) {
64+
failures = append(failures, lint.Failure{
65+
Confidence: 1,
66+
Failure: fmt.Sprintf("import name (%s) must match the regular expression: %s", alias.Name, r.namingRuleRegexp.String()),
67+
Node: alias,
68+
Category: "imports",
69+
})
70+
}
71+
}
72+
73+
return failures
74+
}
75+
76+
// Name returns the rule name.
77+
func (*ImportAliasNamingRule) Name() string {
78+
return "import-alias-naming"
79+
}

test/import-alias-naming_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mgechev/revive/lint"
7+
"github.com/mgechev/revive/rule"
8+
)
9+
10+
func TestImportAliasNaming(t *testing.T) {
11+
testRule(t, "import-alias-naming", &rule.ImportAliasNamingRule{})
12+
testRule(t, "import-alias-naming-custom-config", &rule.ImportAliasNamingRule{}, &lint.RuleConfig{
13+
Arguments: []any{`^[a-z]+$`},
14+
})
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package fixtures
2+
3+
import (
4+
_ "strings"
5+
bar_foo "strings" // MATCH /import name (bar_foo) must match the regular expression: ^[a-z]+$/
6+
fooBAR "strings" // MATCH /import name (fooBAR) must match the regular expression: ^[a-z]+$/
7+
v1 "strings" // MATCH /import name (v1) must match the regular expression: ^[a-z]+$/
8+
magical "magic/hat"
9+
)
10+
11+
func somefunc() {
12+
fooBAR.Clone("")
13+
bar_foo.Clone("")
14+
v1.Clone("")
15+
magical.Clone("")
16+
}

testdata/import-alias-naming.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package fixtures
2+
3+
import (
4+
_ "strings"
5+
bar_foo "strings" // MATCH /import name (bar_foo) must match the regular expression: ^[a-z][a-z0-9]{0,}$/
6+
fooBAR "strings" // MATCH /import name (fooBAR) must match the regular expression: ^[a-z][a-z0-9]{0,}$/
7+
v1 "strings"
8+
magical "magic/hat"
9+
)
10+
11+
func somefunc() {
12+
fooBAR.Clone("")
13+
bar_foo.Clone("")
14+
v1.Clone("")
15+
magical.Clone("")
16+
}

0 commit comments

Comments
 (0)