-
Notifications
You must be signed in to change notification settings - Fork 281
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
842b3e2
commit f74c8fe
Showing
10 changed files
with
1,222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package rule | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"fmt" | ||
"go/ast" | ||
"go/token" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/mgechev/revive/lint" | ||
) | ||
|
||
const defaultFileLengthLimitMax = 1000 | ||
|
||
// FileLengthLimitRule lints the number of lines in a file. | ||
type FileLengthLimitRule struct { | ||
max int | ||
skipComments bool | ||
skipBlankLines bool | ||
sync.Mutex | ||
} | ||
|
||
// Apply applies the rule to given file. | ||
func (r *FileLengthLimitRule) Apply(file *lint.File, arguments lint.Arguments) []lint.Failure { | ||
r.configure(arguments) | ||
|
||
all := 0 | ||
blank := 0 | ||
scanner := bufio.NewScanner(bytes.NewReader(file.Content())) | ||
for scanner.Scan() { | ||
all++ | ||
if len(scanner.Bytes()) == 0 { | ||
blank++ | ||
} | ||
} | ||
|
||
if err := scanner.Err(); err != nil { | ||
panic(err.Error()) | ||
} | ||
|
||
lines := all | ||
if r.skipComments { | ||
lines -= countCommentLines(file.AST.Comments) | ||
} | ||
|
||
if r.skipBlankLines { | ||
lines -= blank | ||
} | ||
|
||
if lines <= r.max { | ||
return nil | ||
} | ||
|
||
return []lint.Failure{ | ||
{ | ||
Category: "code-style", | ||
Confidence: 1, | ||
Position: lint.FailurePosition{ | ||
Start: token.Position{ | ||
Filename: file.Name, | ||
Line: all, | ||
}, | ||
}, | ||
Failure: fmt.Sprintf("file length is %d lines, which exceeds the limit of %d", lines, r.max), | ||
}, | ||
} | ||
} | ||
|
||
func (r *FileLengthLimitRule) configure(arguments lint.Arguments) { | ||
r.Lock() | ||
defer r.Unlock() | ||
|
||
if len(arguments) == 0 { | ||
r.max = defaultFileLengthLimitMax | ||
return | ||
} | ||
|
||
argKV, ok := arguments[0].(map[string]any) | ||
if !ok { | ||
panic(fmt.Sprintf(`invalid argument to the "file-length-limit" rule. Expecting a k,v map, got %T`, arguments[0])) | ||
} | ||
for k, v := range argKV { | ||
switch k { | ||
case "max": | ||
maxLines, ok := v.(int64) | ||
if !ok || maxLines < 1 { | ||
panic(fmt.Sprintf(`invalid configuration value for max lines in "file-length-limit" rule; need int64 but got %T`, arguments[0])) | ||
} | ||
r.max = int(maxLines) | ||
case "skipComments": | ||
skipComments, ok := v.(bool) | ||
if !ok { | ||
panic(fmt.Sprintf(`invalid configuration value for skip comments in "file-length-limit" rule; need bool but got %T`, arguments[1])) | ||
} | ||
r.skipComments = skipComments | ||
case "skipBlankLines": | ||
skipBlankLines, ok := v.(bool) | ||
if !ok { | ||
panic(fmt.Sprintf(`invalid configuration value for skip blank lines in "file-length-limit" rule; need bool but got %T`, arguments[2])) | ||
} | ||
r.skipBlankLines = skipBlankLines | ||
} | ||
} | ||
} | ||
|
||
func (*FileLengthLimitRule) Name() string { | ||
return "file-length-limit" | ||
} | ||
|
||
func countCommentLines(comments []*ast.CommentGroup) int { | ||
count := 0 | ||
for _, cg := range comments { | ||
for _, comment := range cg.List { | ||
switch comment.Text[1] { | ||
case '/': // single-line comment | ||
count++ | ||
case '*': // multi-line comment | ||
count += strings.Count(comment.Text, "\n") + 1 | ||
} | ||
} | ||
} | ||
return count | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/mgechev/revive/lint" | ||
"github.com/mgechev/revive/rule" | ||
) | ||
|
||
func TestFileLengthLimit(t *testing.T) { | ||
testRule(t, "file-length-limit-default", &rule.FileLengthLimitRule{}, &lint.RuleConfig{ | ||
Arguments: []any{}, | ||
}) | ||
testRule(t, "file-length-limit-9", &rule.FileLengthLimitRule{}, &lint.RuleConfig{ | ||
Arguments: []any{map[string]any{"max": int64(9)}}, | ||
}) | ||
testRule(t, "file-length-limit-7-skip-comments", &rule.FileLengthLimitRule{}, &lint.RuleConfig{ | ||
Arguments: []any{map[string]any{"max": int64(7), "skipComments": true}}, | ||
}) | ||
testRule(t, "file-length-limit-6-skip-blank", &rule.FileLengthLimitRule{}, &lint.RuleConfig{ | ||
Arguments: []any{map[string]any{"max": int64(6), "skipBlankLines": true}}, | ||
}) | ||
testRule(t, "file-length-limit-4-skip-comments-skip-blank", &rule.FileLengthLimitRule{}, &lint.RuleConfig{ | ||
Arguments: []any{map[string]any{"max": int64(4), "skipComments": true, "skipBlankLines": true}}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package fixtures | ||
|
||
import "fmt" | ||
|
||
// Foo is a function. | ||
func Foo(a, b int) { | ||
fmt.Println("Hello, world!") | ||
} | ||
|
||
// MATCH /file length is 5 lines, which exceeds the limit of 4/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package fixtures | ||
|
||
import "fmt" | ||
|
||
// Foo is a function. | ||
func Foo(a, b int) { | ||
fmt.Println("Hello, world!") | ||
} | ||
|
||
// MATCH /file length is 7 lines, which exceeds the limit of 6/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package fixtures | ||
|
||
import "fmt" | ||
|
||
// Foo is a function. | ||
func Foo(a, b int) { | ||
// This | ||
/* is | ||
a | ||
*/ | ||
// a comment. | ||
fmt.Println("Hello, world!") | ||
/* | ||
This is | ||
multiline | ||
comment. | ||
*/ | ||
} | ||
|
||
// MATCH /file length is 8 lines, which exceeds the limit of 7/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package fixtures | ||
|
||
import "fmt" | ||
|
||
// Foo is a function. | ||
func Foo(a, b int) { | ||
fmt.Println("Hello, world!") | ||
} | ||
|
||
// MATCH /file length is 10 lines, which exceeds the limit of 9/ |
Oops, something went wrong.