github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/config/config.go (about) 1 package config 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 8 "github.com/songshiyun/revive/formatter" 9 10 "github.com/BurntSushi/toml" 11 "github.com/songshiyun/revive/lint" 12 "github.com/songshiyun/revive/rule" 13 ) 14 15 var defaultRules = []lint.Rule{ 16 &rule.VarDeclarationsRule{}, 17 &rule.PackageCommentsRule{}, 18 &rule.DotImportsRule{}, 19 &rule.BlankImportsRule{}, 20 &rule.ExportedRule{}, 21 &rule.VarNamingRule{}, 22 &rule.IndentErrorFlowRule{}, 23 &rule.RangeRule{}, 24 &rule.ErrorfRule{}, 25 &rule.ErrorNamingRule{}, 26 &rule.ErrorStringsRule{}, 27 &rule.ReceiverNamingRule{}, 28 &rule.IncrementDecrementRule{}, 29 &rule.ErrorReturnRule{}, 30 &rule.UnexportedReturnRule{}, 31 &rule.TimeNamingRule{}, 32 &rule.ContextKeysType{}, 33 &rule.ContextAsArgumentRule{}, 34 } 35 36 var allRules = append([]lint.Rule{ 37 &rule.ArgumentsLimitRule{}, 38 &rule.CyclomaticRule{}, 39 &rule.FileHeaderRule{}, 40 &rule.EmptyBlockRule{}, 41 &rule.SuperfluousElseRule{}, 42 &rule.ConfusingNamingRule{}, 43 &rule.GetReturnRule{}, 44 &rule.ModifiesParamRule{}, 45 &rule.ConfusingResultsRule{}, 46 &rule.DeepExitRule{}, 47 &rule.UnusedParamRule{}, 48 &rule.UnreachableCodeRule{}, 49 &rule.AddConstantRule{}, 50 &rule.FlagParamRule{}, 51 &rule.UnnecessaryStmtRule{}, 52 &rule.StructTagRule{}, 53 &rule.ModifiesValRecRule{}, 54 &rule.ConstantLogicalExprRule{}, 55 &rule.BoolLiteralRule{}, 56 &rule.RedefinesBuiltinIDRule{}, 57 &rule.ImportsBlacklistRule{}, 58 &rule.FunctionResultsLimitRule{}, 59 &rule.MaxPublicStructsRule{}, 60 &rule.RangeValInClosureRule{}, 61 &rule.RangeValAddress{}, 62 &rule.WaitGroupByValueRule{}, 63 &rule.AtomicRule{}, 64 &rule.EmptyLinesRule{}, 65 &rule.LineLengthLimitRule{}, 66 &rule.CallToGCRule{}, 67 &rule.DuplicatedImportsRule{}, 68 &rule.ImportShadowingRule{}, 69 &rule.BareReturnRule{}, 70 &rule.UnusedReceiverRule{}, 71 &rule.UnhandledErrorRule{}, 72 &rule.CognitiveComplexityRule{}, 73 &rule.StringOfIntRule{}, 74 &rule.StringFormatRule{}, 75 &rule.EarlyReturnRule{}, 76 &rule.UnconditionalRecursionRule{}, 77 &rule.IdenticalBranchesRule{}, 78 &rule.DeferRule{}, 79 &rule.UnexportedNamingRule{}, 80 &rule.FunctionLength{}, 81 &rule.NestedStructs{}, 82 &rule.IfReturnRule{}, 83 &rule.UselessBreak{}, 84 &rule.TimeEqualRule{}, 85 &rule.BannedCharsRule{}, 86 &rule.OptimizeOperandsOrderRule{}, 87 }, defaultRules...) 88 89 var allFormatters = []lint.Formatter{ 90 &formatter.Stylish{}, 91 &formatter.Friendly{}, 92 &formatter.JSON{}, 93 &formatter.NDJSON{}, 94 &formatter.Default{}, 95 &formatter.Unix{}, 96 &formatter.Checkstyle{}, 97 &formatter.Plain{}, 98 &formatter.Sarif{}, 99 } 100 101 func getFormatters() map[string]lint.Formatter { 102 result := map[string]lint.Formatter{} 103 for _, f := range allFormatters { 104 result[f.Name()] = f 105 } 106 return result 107 } 108 109 // GetLintingRules yields the linting rules that must be applied by the linter 110 func GetLintingRules(config *lint.Config, extraRules []lint.Rule) ([]lint.Rule, error) { 111 rulesMap := map[string]lint.Rule{} 112 for _, r := range allRules { 113 rulesMap[r.Name()] = r 114 } 115 for _, r := range extraRules { 116 if _, ok := rulesMap[r.Name()]; ok { 117 continue 118 } 119 rulesMap[r.Name()] = r 120 } 121 122 var lintingRules []lint.Rule 123 for name, ruleConfig := range config.Rules { 124 rule, ok := rulesMap[name] 125 if !ok { 126 return nil, fmt.Errorf("cannot find rule: %s", name) 127 } 128 129 if ruleConfig.Disabled { 130 continue // skip disabled rules 131 } 132 133 lintingRules = append(lintingRules, rule) 134 } 135 136 return lintingRules, nil 137 } 138 139 func parseConfig(path string, config *lint.Config) error { 140 file, err := ioutil.ReadFile(path) 141 if err != nil { 142 return errors.New("cannot read the config file") 143 } 144 _, err = toml.Decode(string(file), config) 145 if err != nil { 146 return fmt.Errorf("cannot parse the config file: %v", err) 147 } 148 return nil 149 } 150 151 func normalizeConfig(config *lint.Config) { 152 if len(config.Rules) == 0 { 153 config.Rules = map[string]lint.RuleConfig{} 154 } 155 if config.EnableAllRules { 156 // Add to the configuration all rules not yet present in it 157 for _, rule := range allRules { 158 ruleName := rule.Name() 159 _, alreadyInConf := config.Rules[ruleName] 160 if alreadyInConf { 161 continue 162 } 163 // Add the rule with an empty conf for 164 config.Rules[ruleName] = lint.RuleConfig{} 165 } 166 } 167 168 severity := config.Severity 169 if severity != "" { 170 for k, v := range config.Rules { 171 if v.Severity == "" { 172 v.Severity = severity 173 } 174 config.Rules[k] = v 175 } 176 for k, v := range config.Directives { 177 if v.Severity == "" { 178 v.Severity = severity 179 } 180 config.Directives[k] = v 181 } 182 } 183 } 184 185 const defaultConfidence = 0.8 186 187 func LoadDefaultConfig(data []byte) (*lint.Config, error) { 188 config := &lint.Config{} 189 config.Confidence = defaultConfidence 190 _, err := toml.Decode(string(data), config) 191 if err != nil { 192 return nil, fmt.Errorf("cannot parse the config file: %v", err) 193 } 194 normalizeConfig(config) 195 return config, err 196 } 197 198 // GetConfig yields the configuration 199 func GetConfig(configPath string) (*lint.Config, error) { 200 config := &lint.Config{} 201 switch { 202 case configPath != "": 203 config.Confidence = defaultConfidence 204 err := parseConfig(configPath, config) 205 if err != nil { 206 return nil, err 207 } 208 209 default: // no configuration provided 210 config = defaultConfig() 211 } 212 213 normalizeConfig(config) 214 return config, nil 215 } 216 217 // GetFormatter yields the formatter for lint failures 218 func GetFormatter(formatterName string) (lint.Formatter, error) { 219 formatters := getFormatters() 220 formatter := formatters["default"] 221 if formatterName != "" { 222 f, ok := formatters[formatterName] 223 if !ok { 224 return nil, fmt.Errorf("unknown formatter %v", formatterName) 225 } 226 formatter = f 227 } 228 return formatter, nil 229 } 230 231 func defaultConfig() *lint.Config { 232 defaultConfig := lint.Config{ 233 Confidence: defaultConfidence, 234 Severity: lint.SeverityWarning, 235 Rules: map[string]lint.RuleConfig{}, 236 } 237 for _, r := range defaultRules { 238 defaultConfig.Rules[r.Name()] = lint.RuleConfig{} 239 } 240 return &defaultConfig 241 }