github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/messageNamesUpperCamelCaseRule.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/autodisable"
     7  	"github.com/yoheimuta/protolint/linter/fixer"
     8  	"github.com/yoheimuta/protolint/linter/rule"
     9  
    10  	"github.com/yoheimuta/protolint/linter/report"
    11  	"github.com/yoheimuta/protolint/linter/strs"
    12  	"github.com/yoheimuta/protolint/linter/visitor"
    13  )
    14  
    15  // MessageNamesUpperCamelCaseRule verifies that all message names are CamelCase (with an initial capital).
    16  // See https://developers.google.com/protocol-buffers/docs/style#message-and-field-names.
    17  type MessageNamesUpperCamelCaseRule struct {
    18  	RuleWithSeverity
    19  	fixMode         bool
    20  	autoDisableType autodisable.PlacementType
    21  }
    22  
    23  // NewMessageNamesUpperCamelCaseRule creates a new MessageNamesUpperCamelCaseRule.
    24  func NewMessageNamesUpperCamelCaseRule(
    25  	severity rule.Severity,
    26  	fixMode bool,
    27  	autoDisableType autodisable.PlacementType,
    28  ) MessageNamesUpperCamelCaseRule {
    29  	if autoDisableType != autodisable.Noop {
    30  		fixMode = false
    31  	}
    32  	return MessageNamesUpperCamelCaseRule{
    33  		RuleWithSeverity: RuleWithSeverity{severity: severity},
    34  		fixMode:          fixMode,
    35  		autoDisableType:  autoDisableType,
    36  	}
    37  }
    38  
    39  // ID returns the ID of this rule.
    40  func (r MessageNamesUpperCamelCaseRule) ID() string {
    41  	return "MESSAGE_NAMES_UPPER_CAMEL_CASE"
    42  }
    43  
    44  // Purpose returns the purpose of this rule.
    45  func (r MessageNamesUpperCamelCaseRule) Purpose() string {
    46  	return "Verifies that all message names are CamelCase (with an initial capital)."
    47  }
    48  
    49  // IsOfficial decides whether or not this rule belongs to the official guide.
    50  func (r MessageNamesUpperCamelCaseRule) IsOfficial() bool {
    51  	return true
    52  }
    53  
    54  // Apply applies the rule to the proto.
    55  func (r MessageNamesUpperCamelCaseRule) Apply(proto *parser.Proto) ([]report.Failure, error) {
    56  	base, err := visitor.NewBaseFixableVisitor(r.ID(), r.fixMode, proto, string(r.Severity()))
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	v := &messageNamesUpperCamelCaseVisitor{
    62  		BaseFixableVisitor: base,
    63  	}
    64  	return visitor.RunVisitorAutoDisable(v, proto, r.ID(), r.autoDisableType)
    65  }
    66  
    67  type messageNamesUpperCamelCaseVisitor struct {
    68  	*visitor.BaseFixableVisitor
    69  }
    70  
    71  // VisitMessage checks the message.
    72  func (v *messageNamesUpperCamelCaseVisitor) VisitMessage(message *parser.Message) bool {
    73  	name := message.MessageName
    74  	if !strs.IsUpperCamelCase(name) {
    75  		expected := strs.ToUpperCamelCase(name)
    76  		v.AddFailuref(message.Meta.Pos, "Message name %q must be UpperCamelCase like %q", name, expected)
    77  
    78  		err := v.Fixer.SearchAndReplace(message.Meta.Pos, func(lex *lexer.Lexer) fixer.TextEdit {
    79  			lex.NextKeyword()
    80  			lex.Next()
    81  			return fixer.TextEdit{
    82  				Pos:     lex.Pos.Offset,
    83  				End:     lex.Pos.Offset + len(lex.Text) - 1,
    84  				NewText: []byte(expected),
    85  			}
    86  		})
    87  		if err != nil {
    88  			panic(err)
    89  		}
    90  	}
    91  	return true
    92  }