github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/enumFieldNamesPrefixRule.go (about) 1 package rules 2 3 import ( 4 "strings" 5 6 "github.com/yoheimuta/go-protoparser/v4/lexer" 7 "github.com/yoheimuta/protolint/linter/autodisable" 8 "github.com/yoheimuta/protolint/linter/fixer" 9 "github.com/yoheimuta/protolint/linter/rule" 10 11 "github.com/yoheimuta/protolint/linter/strs" 12 13 "github.com/yoheimuta/go-protoparser/v4/parser" 14 "github.com/yoheimuta/protolint/linter/report" 15 "github.com/yoheimuta/protolint/linter/visitor" 16 ) 17 18 // EnumFieldNamesPrefixRule verifies that enum field names are prefixed with its ENUM_NAME_UPPER_SNAKE_CASE. 19 // See https://developers.google.com/protocol-buffers/docs/style#enums. 20 type EnumFieldNamesPrefixRule struct { 21 RuleWithSeverity 22 fixMode bool 23 autoDisableType autodisable.PlacementType 24 } 25 26 // NewEnumFieldNamesPrefixRule creates a new EnumFieldNamesPrefixRule. 27 func NewEnumFieldNamesPrefixRule( 28 severity rule.Severity, 29 fixMode bool, 30 autoDisableType autodisable.PlacementType, 31 ) EnumFieldNamesPrefixRule { 32 if autoDisableType != autodisable.Noop { 33 fixMode = false 34 } 35 return EnumFieldNamesPrefixRule{ 36 RuleWithSeverity: RuleWithSeverity{severity: severity}, 37 fixMode: fixMode, 38 autoDisableType: autoDisableType, 39 } 40 } 41 42 // ID returns the ID of this rule. 43 func (r EnumFieldNamesPrefixRule) ID() string { 44 return "ENUM_FIELD_NAMES_PREFIX" 45 } 46 47 // Purpose returns the purpose of this rule. 48 func (r EnumFieldNamesPrefixRule) Purpose() string { 49 return `Verifies that enum field names are prefixed with its ENUM_NAME_UPPER_SNAKE_CASE.` 50 } 51 52 // IsOfficial decides whether or not this rule belongs to the official guide. 53 func (r EnumFieldNamesPrefixRule) IsOfficial() bool { 54 return true 55 } 56 57 // Apply applies the rule to the proto. 58 func (r EnumFieldNamesPrefixRule) Apply(proto *parser.Proto) ([]report.Failure, error) { 59 base, err := visitor.NewBaseFixableVisitor(r.ID(), r.fixMode, proto, string(r.Severity())) 60 if err != nil { 61 return nil, err 62 } 63 64 v := &enumFieldNamesPrefixVisitor{ 65 BaseFixableVisitor: base, 66 } 67 return visitor.RunVisitorAutoDisable(v, proto, r.ID(), r.autoDisableType) 68 } 69 70 type enumFieldNamesPrefixVisitor struct { 71 *visitor.BaseFixableVisitor 72 enumName string 73 } 74 75 // VisitEnum checks the enum. 76 func (v *enumFieldNamesPrefixVisitor) VisitEnum(enum *parser.Enum) bool { 77 v.enumName = enum.EnumName 78 return true 79 } 80 81 // VisitEnumField checks the enum field. 82 func (v *enumFieldNamesPrefixVisitor) VisitEnumField(field *parser.EnumField) bool { 83 expectedPrefix := strs.ToUpperSnakeCase(v.enumName) 84 if !strings.HasPrefix(field.Ident, expectedPrefix) { 85 v.AddFailuref(field.Meta.Pos, "EnumField name %q should have the prefix %q", field.Ident, expectedPrefix) 86 87 expected := expectedPrefix + "_" + field.Ident 88 err := v.Fixer.SearchAndReplace(field.Meta.Pos, func(lex *lexer.Lexer) fixer.TextEdit { 89 lex.Next() 90 return fixer.TextEdit{ 91 Pos: lex.Pos.Offset, 92 End: lex.Pos.Offset + len(lex.Text) - 1, 93 NewText: []byte(expected), 94 } 95 }) 96 if err != nil { 97 panic(err) 98 } 99 } 100 return false 101 }