github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/maxLineLengthRule.go (about) 1 package rules 2 3 import ( 4 "bufio" 5 "os" 6 "strings" 7 "unicode/utf8" 8 9 "github.com/yoheimuta/go-protoparser/v4/parser" 10 "github.com/yoheimuta/go-protoparser/v4/parser/meta" 11 12 "github.com/yoheimuta/protolint/linter/disablerule" 13 "github.com/yoheimuta/protolint/linter/report" 14 "github.com/yoheimuta/protolint/linter/rule" 15 ) 16 17 const ( 18 // Keep the line length to 80 characters. 19 // See https://developers.google.com/protocol-buffers/docs/style#standard-file-formatting 20 defaultMaxChars = 80 21 22 defaultTabChars = 4 23 ) 24 25 // MaxLineLengthRule enforces a maximum line length to increase code readability and maintainability. 26 // The length of a line is defined as the number of Unicode characters in the line. 27 type MaxLineLengthRule struct { 28 RuleWithSeverity 29 maxChars int 30 tabChars int 31 } 32 33 // NewMaxLineLengthRule creates a new MaxLineLengthRule. 34 func NewMaxLineLengthRule( 35 severity rule.Severity, 36 maxChars int, 37 tabChars int, 38 ) MaxLineLengthRule { 39 if maxChars == 0 { 40 maxChars = defaultMaxChars 41 } 42 if tabChars == 0 { 43 tabChars = defaultTabChars 44 } 45 return MaxLineLengthRule{ 46 RuleWithSeverity: RuleWithSeverity{severity: severity}, 47 maxChars: maxChars, 48 tabChars: tabChars, 49 } 50 } 51 52 // ID returns the ID of this rule. 53 func (r MaxLineLengthRule) ID() string { 54 return "MAX_LINE_LENGTH" 55 } 56 57 // Purpose returns the purpose of this rule. 58 func (r MaxLineLengthRule) Purpose() string { 59 return "Enforces a maximum line length." 60 } 61 62 // IsOfficial decides whether or not this rule belongs to the official guide. 63 func (r MaxLineLengthRule) IsOfficial() bool { 64 return true 65 } 66 67 // Apply applies the rule to the proto. 68 func (r MaxLineLengthRule) Apply(proto *parser.Proto) ( 69 failures []report.Failure, 70 err error, 71 ) { 72 fileName := proto.Meta.Filename 73 reader, err := os.Open(fileName) 74 if err != nil { 75 return nil, err 76 } 77 defer func() { 78 closeErr := reader.Close() 79 if err != nil { 80 return 81 } 82 if closeErr != nil { 83 err = closeErr 84 } 85 }() 86 87 var lines []string 88 scanner := bufio.NewScanner(reader) 89 for scanner.Scan() { 90 lines = append(lines, scanner.Text()) 91 } 92 93 if err := scanner.Err(); err != nil { 94 return nil, err 95 } 96 97 disablerule.NewInterpreter(r.ID()).CallEachIfValid( 98 lines, 99 func(index int, line string) { 100 line = strings.Replace(line, "\t", strings.Repeat(" ", r.tabChars), -1) 101 lineCount := utf8.RuneCountInString(line) 102 if r.maxChars < lineCount { 103 failures = append(failures, report.Failuref( 104 meta.Position{ 105 Filename: fileName, 106 Line: index + 1, 107 Column: 1, 108 }, 109 r.ID(), 110 "The line length is %d, but it must be shorter than %d", 111 lineCount, 112 r.maxChars, 113 )) 114 } 115 }, 116 ) 117 return failures, nil 118 }