github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/proto3FieldsAvoidRequiredRule.go (about) 1 package rules 2 3 import ( 4 "github.com/yoheimuta/go-protoparser/v4/lexer" 5 "github.com/yoheimuta/go-protoparser/v4/parser" 6 "github.com/yoheimuta/protolint/linter/fixer" 7 "github.com/yoheimuta/protolint/linter/report" 8 "github.com/yoheimuta/protolint/linter/rule" 9 "github.com/yoheimuta/protolint/linter/visitor" 10 ) 11 12 // Proto3FieldsAvoidRequiredRule verifies that all fields should avoid required for proto3. 13 // See https://developers.google.com/protocol-buffers/docs/style#things-to-avoid 14 type Proto3FieldsAvoidRequiredRule struct { 15 RuleWithSeverity 16 fixMode bool 17 } 18 19 // NewProto3FieldsAvoidRequiredRule creates a new Proto3FieldsAvoidRequiredRule. 20 func NewProto3FieldsAvoidRequiredRule( 21 severity rule.Severity, 22 fixMode bool, 23 ) Proto3FieldsAvoidRequiredRule { 24 return Proto3FieldsAvoidRequiredRule{ 25 RuleWithSeverity: RuleWithSeverity{severity: severity}, 26 fixMode: fixMode, 27 } 28 } 29 30 // ID returns the ID of this rule. 31 func (r Proto3FieldsAvoidRequiredRule) ID() string { 32 return "PROTO3_FIELDS_AVOID_REQUIRED" 33 } 34 35 // Purpose returns the purpose of this rule. 36 func (r Proto3FieldsAvoidRequiredRule) Purpose() string { 37 return "Verifies that all fields should avoid required for proto3." 38 } 39 40 // IsOfficial decides whether or not this rule belongs to the official guide. 41 func (r Proto3FieldsAvoidRequiredRule) IsOfficial() bool { 42 return true 43 } 44 45 // Apply applies the rule to the proto. 46 func (r Proto3FieldsAvoidRequiredRule) Apply(proto *parser.Proto) ([]report.Failure, error) { 47 base, err := visitor.NewBaseFixableVisitor(r.ID(), r.fixMode, proto, string(r.Severity())) 48 if err != nil { 49 return nil, err 50 } 51 52 v := &proto3FieldsAvoidRequiredVisitor{ 53 BaseFixableVisitor: base, 54 } 55 return visitor.RunVisitor(v, proto, r.ID()) 56 } 57 58 type proto3FieldsAvoidRequiredVisitor struct { 59 *visitor.BaseFixableVisitor 60 isProto3 bool 61 } 62 63 // VisitSyntax checks the syntax. 64 func (v *proto3FieldsAvoidRequiredVisitor) VisitSyntax(s *parser.Syntax) bool { 65 v.isProto3 = s.ProtobufVersion == "proto3" 66 return false 67 } 68 69 // VisitField checks the field. 70 func (v *proto3FieldsAvoidRequiredVisitor) VisitField(field *parser.Field) bool { 71 if v.isProto3 && field.IsRequired { 72 v.AddFailuref(field.Meta.Pos, `Field %q should avoid required for proto3`, field.FieldName) 73 74 err := v.Fixer.SearchAndReplace(field.Meta.Pos, func(lex *lexer.Lexer) fixer.TextEdit { 75 lex.NextKeyword() 76 return fixer.TextEdit{ 77 Pos: lex.Pos.Offset, 78 End: lex.Pos.Offset + len(lex.Text), 79 NewText: []byte(""), 80 } 81 }) 82 if err != nil { 83 panic(err) 84 } 85 } 86 return false 87 }