github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/fieldNamesExcludePrepositionsRule.go (about) 1 package rules 2 3 import ( 4 "strings" 5 6 "github.com/yoheimuta/go-protoparser/v4/parser" 7 8 "github.com/yoheimuta/protolint/internal/stringsutil" 9 "github.com/yoheimuta/protolint/linter/report" 10 "github.com/yoheimuta/protolint/linter/rule" 11 "github.com/yoheimuta/protolint/linter/strs" 12 "github.com/yoheimuta/protolint/linter/visitor" 13 ) 14 15 // Default values are a conservative list picked out from all preposition candidates. 16 // See https://www.talkenglish.com/vocabulary/top-50-prepositions.aspx 17 var defaultPrepositions = []string{ 18 "of", 19 "with", 20 "at", 21 "from", 22 "into", 23 "during", 24 "including", 25 "until", 26 "against", 27 "among", 28 "throughout", 29 "despite", 30 "towards", 31 "upon", 32 "concerning", 33 34 "to", 35 "in", 36 "for", 37 "on", 38 "by", 39 "about", 40 } 41 42 // FieldNamesExcludePrepositionsRule verifies that all field names don't include prepositions (e.g. "for", "during", "at"). 43 // It is assumed that the field names are underscore_separated_names. 44 // See https://cloud.google.com/apis/design/naming_convention#field_names. 45 type FieldNamesExcludePrepositionsRule struct { 46 RuleWithSeverity 47 prepositions []string 48 excludes []string 49 } 50 51 // NewFieldNamesExcludePrepositionsRule creates a new FieldNamesExcludePrepositionsRule. 52 func NewFieldNamesExcludePrepositionsRule( 53 severity rule.Severity, 54 prepositions []string, 55 excludes []string, 56 ) FieldNamesExcludePrepositionsRule { 57 if len(prepositions) == 0 { 58 prepositions = defaultPrepositions 59 } 60 return FieldNamesExcludePrepositionsRule{ 61 RuleWithSeverity: RuleWithSeverity{severity: severity}, 62 prepositions: prepositions, 63 excludes: excludes, 64 } 65 } 66 67 // ID returns the ID of this rule. 68 func (r FieldNamesExcludePrepositionsRule) ID() string { 69 return "FIELD_NAMES_EXCLUDE_PREPOSITIONS" 70 } 71 72 // Purpose returns the purpose of this rule. 73 func (r FieldNamesExcludePrepositionsRule) Purpose() string { 74 return `Verifies that all field names don't include prepositions (e.g. "for", "during", "at").` 75 } 76 77 // IsOfficial decides whether or not this rule belongs to the official guide. 78 func (r FieldNamesExcludePrepositionsRule) IsOfficial() bool { 79 return false 80 } 81 82 // Apply applies the rule to the proto. 83 func (r FieldNamesExcludePrepositionsRule) Apply(proto *parser.Proto) ([]report.Failure, error) { 84 v := &fieldNamesExcludePrepositionsVisitor{ 85 BaseAddVisitor: visitor.NewBaseAddVisitor(r.ID(), string(r.Severity())), 86 prepositions: r.prepositions, 87 excludes: r.excludes, 88 } 89 return visitor.RunVisitor(v, proto, r.ID()) 90 } 91 92 type fieldNamesExcludePrepositionsVisitor struct { 93 *visitor.BaseAddVisitor 94 prepositions []string 95 excludes []string 96 } 97 98 // VisitField checks the field. 99 func (v *fieldNamesExcludePrepositionsVisitor) VisitField(field *parser.Field) bool { 100 name := field.FieldName 101 for _, e := range v.excludes { 102 name = strings.Replace(name, e, "", -1) 103 } 104 105 parts := strs.SplitSnakeCaseWord(name) 106 for _, p := range parts { 107 if stringsutil.ContainsStringInSlice(p, v.prepositions) { 108 v.AddFailuref(field.Meta.Pos, "Field name %q should not include a preposition %q", field.FieldName, p) 109 } 110 } 111 return false 112 } 113 114 // VisitMapField checks the map field. 115 func (v *fieldNamesExcludePrepositionsVisitor) VisitMapField(field *parser.MapField) bool { 116 name := field.MapName 117 for _, e := range v.excludes { 118 name = strings.Replace(name, e, "", -1) 119 } 120 121 parts := strs.SplitSnakeCaseWord(name) 122 for _, p := range parts { 123 if stringsutil.ContainsStringInSlice(p, v.prepositions) { 124 v.AddFailuref(field.Meta.Pos, "Field name %q should not include a preposition %q", field.MapName, p) 125 } 126 } 127 return false 128 } 129 130 // VisitOneofField checks the oneof field. 131 func (v *fieldNamesExcludePrepositionsVisitor) VisitOneofField(field *parser.OneofField) bool { 132 name := field.FieldName 133 for _, e := range v.excludes { 134 name = strings.Replace(name, e, "", -1) 135 } 136 137 parts := strs.SplitSnakeCaseWord(name) 138 for _, p := range parts { 139 if stringsutil.ContainsStringInSlice(p, v.prepositions) { 140 v.AddFailuref(field.Meta.Pos, "Field name %q should not include a preposition %q", field.FieldName, p) 141 } 142 } 143 return false 144 }