125 lines
4.2 KiB
Go
125 lines
4.2 KiB
Go
package editorconfig
|
|
|
|
import (
|
|
"github.com/saintfish/chardet"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var fullFileCheckers = map[string]FullFileChecker{
|
|
"end_of_line": CheckEndOfLineRule,
|
|
"insert_final_newline": CheckInsertFinalNewLineRule,
|
|
"charset": CheckCharsetRule,
|
|
}
|
|
|
|
type FullFileChecker func(ruleValue string, fileContent string) *FullFileCheckResult
|
|
|
|
// @todo - add fixers to each instance of FullFileCheckResult.
|
|
type FullFileCheckResult struct {
|
|
isOk bool
|
|
messageIfNotOk string
|
|
}
|
|
|
|
var lfRegexp = regexp.MustCompile(`\n`)
|
|
var crRegexp = regexp.MustCompile(`\r`)
|
|
var crlfRegexp = regexp.MustCompile(`\r\n`)
|
|
|
|
func CheckEndOfLineRule(ruleValue string, fileContent string) *FullFileCheckResult {
|
|
// Valid rules values are "lf", "cr", or "crlf". The values are case insensitive.
|
|
ruleValueLowercase := strings.ToLower(ruleValue)
|
|
|
|
if ruleValueLowercase != "lf" && ruleValueLowercase != "cr" && ruleValueLowercase != "crlf" {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "end_of_line value is not valid: " + ruleValue}
|
|
}
|
|
|
|
if ruleValueLowercase == "lf" {
|
|
if crlfRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should use LF for new lines but contains CRLF"}
|
|
}
|
|
if crRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should use LF for new lines but contains CR"}
|
|
}
|
|
}
|
|
|
|
if ruleValueLowercase == "cr" {
|
|
if crlfRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should use CR for new lines but contains CRLF"}
|
|
}
|
|
if lfRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should use CR for new lines but contains LF"}
|
|
}
|
|
}
|
|
|
|
if ruleValueLowercase == "crlf" {
|
|
fileContent := crlfRegexp.ReplaceAllString(fileContent, "")
|
|
if lfRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should use CRLF for new lines but contains LF"}
|
|
}
|
|
if crRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should use CRLF for new lines but contains CR"}
|
|
}
|
|
}
|
|
|
|
return &FullFileCheckResult{isOk: true}
|
|
}
|
|
|
|
var endsWithFinalNewLineRegexp = regexp.MustCompile(`(\n|\r|\r\n)$`)
|
|
|
|
func CheckInsertFinalNewLineRule(ruleValue string, fileContent string) *FullFileCheckResult {
|
|
// Valid rules values are "true" or "false". The values are case insensitive.
|
|
ruleValueLowercase := strings.ToLower(ruleValue)
|
|
|
|
if ruleValueLowercase != "true" && ruleValueLowercase != "false" {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "insert_final_new_line value should be true or false, is: " + ruleValue}
|
|
}
|
|
|
|
if len(fileContent) == 0 {
|
|
return &FullFileCheckResult{isOk: true}
|
|
}
|
|
|
|
if ruleValueLowercase == "true" {
|
|
if endsWithFinalNewLineRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: true}
|
|
} else {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should end with an empty line but it does not"}
|
|
}
|
|
}
|
|
|
|
if ruleValueLowercase == "false" {
|
|
if !endsWithFinalNewLineRegexp.MatchString(fileContent) {
|
|
return &FullFileCheckResult{isOk: true}
|
|
} else {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "should not end with an empty line but it does"}
|
|
}
|
|
}
|
|
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "unexpected condition"}
|
|
}
|
|
|
|
func CheckCharsetRule(ruleValue string, fileContent string) *FullFileCheckResult {
|
|
// Valid rules values are "latin1", "utf-8", "utf-8-bom", "utf-16be" or "utf-16le".
|
|
if ruleValue != "latin1" && ruleValue != "utf-8" && ruleValue != "utf-8-bom" && ruleValue != "utf-16be" && ruleValue != "utf-16le" {
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "charset value is invalid: " + ruleValue}
|
|
}
|
|
|
|
detector := chardet.NewTextDetector()
|
|
|
|
bestGuess, err := detector.DetectBest([]byte(fileContent))
|
|
if err != nil {
|
|
ExitBecauseOfInternalError(err.Error())
|
|
}
|
|
|
|
actual := strings.ToLower(bestGuess.Charset)
|
|
|
|
if ruleValue == actual {
|
|
return &FullFileCheckResult{isOk: true}
|
|
}
|
|
|
|
if ruleValue == "utf-8" && strings.HasPrefix(actual, "iso-8859-") {
|
|
// iso-8859-* is a subset of utf-8.
|
|
return &FullFileCheckResult{isOk: true}
|
|
}
|
|
|
|
return &FullFileCheckResult{isOk: false, messageIfNotOk: "expected " + ruleValue + " but is: " + actual}
|
|
}
|