github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/quoteConsistentRule.go (about) 1 package rules 2 3 import ( 4 "strings" 5 6 "github.com/yoheimuta/go-protoparser/v4/parser" 7 "github.com/yoheimuta/protolint/internal/linter/config" 8 "github.com/yoheimuta/protolint/linter/report" 9 "github.com/yoheimuta/protolint/linter/rule" 10 "github.com/yoheimuta/protolint/linter/visitor" 11 ) 12 13 // QuoteConsistentRule verifies that the use of quote for strings is consistent. 14 type QuoteConsistentRule struct { 15 RuleWithSeverity 16 quote config.QuoteType 17 18 fixMode bool 19 } 20 21 // NewQuoteConsistentRule creates a new QuoteConsistentRule. 22 func NewQuoteConsistentRule( 23 severity rule.Severity, 24 quote config.QuoteType, 25 fixMode bool, 26 ) QuoteConsistentRule { 27 return QuoteConsistentRule{ 28 RuleWithSeverity: RuleWithSeverity{severity: severity}, 29 quote: quote, 30 fixMode: fixMode, 31 } 32 } 33 34 // ID returns the ID of this rule. 35 func (r QuoteConsistentRule) ID() string { 36 return "QUOTE_CONSISTENT" 37 } 38 39 // Purpose returns the purpose of this rule. 40 func (r QuoteConsistentRule) Purpose() string { 41 return "Verifies that the use of quote for strings is consistent." 42 } 43 44 // IsOfficial decides whether or not this rule belongs to the official guide. 45 func (r QuoteConsistentRule) IsOfficial() bool { 46 return true 47 } 48 49 // Apply applies the rule to the proto. 50 func (r QuoteConsistentRule) Apply(proto *parser.Proto) ([]report.Failure, error) { 51 base, err := visitor.NewBaseFixableVisitor(r.ID(), r.fixMode, proto, string(r.Severity())) 52 if err != nil { 53 return nil, err 54 } 55 56 v := "eConsistentVisitor{ 57 BaseFixableVisitor: base, 58 quote: r.quote, 59 } 60 return visitor.RunVisitor(v, proto, r.ID()) 61 } 62 63 type quoteConsistentVisitor struct { 64 *visitor.BaseFixableVisitor 65 quote config.QuoteType 66 } 67 68 func (v quoteConsistentVisitor) VisitSyntax(s *parser.Syntax) bool { 69 str := s.ProtobufVersionQuote 70 converted := convertConsistentQuote(str, v.quote) 71 if str != converted { 72 v.AddFailuref(s.Meta.Pos, "Quoted string should be %s but was %s.", converted, str) 73 v.Fixer.ReplaceText(s.Meta.Pos.Line, str, converted) 74 } 75 return false 76 } 77 78 func (v quoteConsistentVisitor) VisitImport(i *parser.Import) (next bool) { 79 str := i.Location 80 converted := convertConsistentQuote(str, v.quote) 81 if str != converted { 82 v.AddFailuref(i.Meta.Pos, "Quoted string should be %s but was %s.", converted, str) 83 v.Fixer.ReplaceText(i.Meta.Pos.Line, str, converted) 84 } 85 return false 86 } 87 88 func (v quoteConsistentVisitor) VisitOption(o *parser.Option) (next bool) { 89 str := o.Constant 90 converted := convertConsistentQuote(str, v.quote) 91 if str != converted { 92 v.AddFailuref(o.Meta.Pos, "Quoted string should be %s but was %s.", converted, str) 93 v.Fixer.ReplaceText(o.Meta.Pos.Line, str, converted) 94 } 95 return false 96 } 97 98 func (v quoteConsistentVisitor) VisitEnumField(f *parser.EnumField) (next bool) { 99 for _, option := range f.EnumValueOptions { 100 str := option.Constant 101 converted := convertConsistentQuote(str, v.quote) 102 if str != converted { 103 v.AddFailuref(f.Meta.Pos, "Quoted string should be %s but was %s.", converted, str) 104 v.Fixer.ReplaceText(f.Meta.Pos.Line, str, converted) 105 } 106 } 107 return false 108 } 109 110 func (v quoteConsistentVisitor) VisitField(f *parser.Field) (next bool) { 111 for _, option := range f.FieldOptions { 112 str := option.Constant 113 converted := convertConsistentQuote(str, v.quote) 114 if str != converted { 115 v.AddFailuref(f.Meta.Pos, "Quoted string should be %s but was %s.", converted, str) 116 v.Fixer.ReplaceText(f.Meta.Pos.Line, str, converted) 117 } 118 } 119 return false 120 } 121 122 func convertConsistentQuote(s string, quote config.QuoteType) string { 123 var valid, invalid string 124 if quote == config.DoubleQuote { 125 valid, invalid = "\"", "'" 126 } else { 127 valid, invalid = "'", "\"" 128 } 129 130 if strings.HasPrefix(s, invalid) && strings.HasSuffix(s, invalid) { 131 return valid + s[1:len(s)-1] + valid 132 } 133 return s 134 }