github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/packageNameLowerCaseRule.go (about)

     1  package rules
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/yoheimuta/go-protoparser/v4/lexer"
     7  	"github.com/yoheimuta/go-protoparser/v4/parser"
     8  	"github.com/yoheimuta/protolint/linter/fixer"
     9  	"github.com/yoheimuta/protolint/linter/rule"
    10  
    11  	"github.com/yoheimuta/protolint/linter/report"
    12  	"github.com/yoheimuta/protolint/linter/strs"
    13  	"github.com/yoheimuta/protolint/linter/visitor"
    14  )
    15  
    16  // PackageNameLowerCaseRule verifies that the package name doesn't contain any uppercase letters.
    17  // See https://developers.google.com/protocol-buffers/docs/style#packages.
    18  type PackageNameLowerCaseRule struct {
    19  	RuleWithSeverity
    20  	fixMode bool
    21  }
    22  
    23  // NewPackageNameLowerCaseRule creates a new PackageNameLowerCaseRule.
    24  func NewPackageNameLowerCaseRule(
    25  	severity rule.Severity,
    26  	fixMode bool,
    27  ) PackageNameLowerCaseRule {
    28  	return PackageNameLowerCaseRule{
    29  		RuleWithSeverity: RuleWithSeverity{severity: severity},
    30  		fixMode:          fixMode,
    31  	}
    32  }
    33  
    34  // ID returns the ID of this rule.
    35  func (r PackageNameLowerCaseRule) ID() string {
    36  	return "PACKAGE_NAME_LOWER_CASE"
    37  }
    38  
    39  // Purpose returns the purpose of this rule.
    40  func (r PackageNameLowerCaseRule) Purpose() string {
    41  	return "Verifies that the package name doesn't contain any uppercase letters."
    42  }
    43  
    44  // IsOfficial decides whether or not this rule belongs to the official guide.
    45  func (r PackageNameLowerCaseRule) IsOfficial() bool {
    46  	return true
    47  }
    48  
    49  // Apply applies the rule to the proto.
    50  func (r PackageNameLowerCaseRule) 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 := &packageNameLowerCaseVisitor{
    57  		BaseFixableVisitor: base,
    58  	}
    59  	return visitor.RunVisitor(v, proto, r.ID())
    60  }
    61  
    62  type packageNameLowerCaseVisitor struct {
    63  	*visitor.BaseFixableVisitor
    64  }
    65  
    66  // VisitPackage checks the package.
    67  func (v *packageNameLowerCaseVisitor) VisitPackage(p *parser.Package) bool {
    68  	name := p.Name
    69  	if !isPackageLowerCase(name) {
    70  		expected := strings.ToLower(name)
    71  		v.AddFailuref(p.Meta.Pos, "Package name %q must not contain any uppercase letter. Consider to change like %q.", name, expected)
    72  
    73  		err := v.Fixer.SearchAndReplace(p.Meta.Pos, func(lex *lexer.Lexer) fixer.TextEdit {
    74  			lex.NextKeyword()
    75  			ident, startPos, _ := lex.ReadFullIdent()
    76  			return fixer.TextEdit{
    77  				Pos:     startPos.Offset,
    78  				End:     startPos.Offset + len(ident) - 1,
    79  				NewText: []byte(expected),
    80  			}
    81  		})
    82  		if err != nil {
    83  			panic(err)
    84  		}
    85  	}
    86  	return false
    87  }
    88  
    89  func isPackageLowerCase(packageName string) bool {
    90  	return !strs.HasAnyUpperCase(packageName)
    91  }