Skip to content

Commit

Permalink
lint: factorize local definition
Browse files Browse the repository at this point in the history
Signed-off-by: Yoan Blanc <[email protected]>
  • Loading branch information
greut committed Jan 28, 2020
1 parent 0920c51 commit cb207ae
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 152 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ go test:
eclint:
stage: lint
script:
- go build -o eclint cmd/eclint/main.go
- go build -o eclint gitlab.com/greut/eclint/cmd/eclint
- ./eclint -exclude "testdata/**/*"

golangci-lint:
Expand Down
15 changes: 15 additions & 0 deletions cmd/eclint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ var (
version = "dev"
)

const (
overridePrefix = "eclint_"
)

func main() { //nolint:funlen
flagVersion := false
forceColors := false
Expand Down Expand Up @@ -73,6 +77,9 @@ func main() { //nolint:funlen

if opt.Summary {
opt.ShowAllErrors = true
}

if opt.ShowAllErrors {
opt.ShowErrorQuantity = 0
}

Expand Down Expand Up @@ -136,6 +143,14 @@ func main() { //nolint:funlen
break
}

err = eclint.OverrideDefinitionUsingPrefix(def, overridePrefix)
if err != nil {
log.Error(err, "overriding the definition failed", "prefix", overridePrefix)
c++

break
}

errs := eclint.LintWithDefinition(def, filename, opt.Log.WithValues("filename", filename))
c += len(errs)

Expand Down
110 changes: 110 additions & 0 deletions definition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package eclint

import (
"fmt"
"strconv"
"strings"

"github.com/editorconfig/editorconfig-core-go/v2"
)

// definition contains the fields that aren't native to EditorConfig.Definition
type definition struct {
editorconfig.Definition
BlockCommentStart []byte
BlockComment []byte
BlockCommentEnd []byte
MaxLength int
TabWidth int
IndentSize int
LastLine []byte
LastIndex int
InsideBlockComment bool
}

func newDefinition(d *editorconfig.Definition) (*definition, error) {
def := &definition{
Definition: *d,
TabWidth: d.TabWidth,
}

if d.IndentSize != "" && d.IndentSize != UnsetValue {
is, err := strconv.Atoi(d.IndentSize)
if err != nil {
return nil, err
}

def.IndentSize = is
}

if def.IndentStyle != "" && def.IndentStyle != UnsetValue {
bs, ok := def.Raw["block_comment_start"]
if ok && bs != "" && bs != UnsetValue {
def.BlockCommentStart = []byte(bs)
bc, ok := def.Raw["block_comment"]

if ok && bc != "" && bs != UnsetValue {
def.BlockComment = []byte(bc)
}

be, ok := def.Raw["block_comment_end"]
if !ok || be == "" || be == UnsetValue {
return nil, fmt.Errorf(".editorconfig: block_comment_end was expected, none were found")
}

def.BlockCommentEnd = []byte(be)
}
}

if mll, ok := def.Raw["max_line_length"]; ok && mll != "off" && mll != UnsetValue {
ml, er := strconv.Atoi(mll)
if er != nil || ml < 0 {
return nil, fmt.Errorf(".editorconfig: max_line_length expected a non-negative number, got %q", mll)
}

def.MaxLength = ml

if def.TabWidth <= 0 {
def.TabWidth = DefaultTabWidth
}
}

return def, nil
}

// OverrideDefinitionUsingPrefix is an helper that takes the prefixed values.
//
// It replaces thoses values into the nominal ones. That way a tool could a
// different set of definition than the real editor would.
func OverrideDefinitionUsingPrefix(def *editorconfig.Definition, prefix string) error {
for k, v := range def.Raw {
if strings.HasPrefix(k, prefix) {
nk := k[len(prefix):]
def.Raw[nk] = v

switch nk {
case "indent_style":
def.IndentStyle = v
case "indent_size":
def.IndentSize = v
case "charset":
def.Charset = v
case "end_of_line":
def.EndOfLine = v
case "tab_width":
i, err := strconv.Atoi(v)
if err != nil {
return fmt.Errorf("tab_width cannot be set. %w", err)
}

def.TabWidth = i
case "trim_trailing_whitespace":
return fmt.Errorf("%v cannot be overridden yet, pr welcome", nk)
case "insert_final_newline":
return fmt.Errorf("%v cannot be overridden yet, pr welcome", nk)
}
}
}

return nil
}
44 changes: 44 additions & 0 deletions definition_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package eclint_test

import (
"testing"

"github.com/editorconfig/editorconfig-core-go/v2"
"gitlab.com/greut/eclint"
)

func TestOverridingUsingPrefix(t *testing.T) {
def := &editorconfig.Definition{
Charset: "utf-8 bom",
IndentStyle: "tab",
IndentSize: "3",
TabWidth: 3,
}

raw := make(map[string]string)
raw["@_charset"] = "unset"
raw["@_indent_style"] = "space"
raw["@_indent_size"] = "4"
raw["@_tab_width"] = "4"
def.Raw = raw

if err := eclint.OverrideDefinitionUsingPrefix(def, "@_"); err != nil {
t.Fatal(err)
}

if def.Charset != "unset" {
t.Errorf("charset not changed, got %q", def.Charset)
}

if def.IndentStyle != "space" {
t.Errorf("indent_style not changed, got %q", def.IndentStyle)
}

if def.IndentSize != "4" {
t.Errorf("indent_size not changed, got %q", def.IndentSize)
}

if def.TabWidth != 4 {
t.Errorf("tab_width not changed, got %d", def.TabWidth)
}
}
122 changes: 18 additions & 104 deletions lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"

"github.com/editorconfig/editorconfig-core-go/v2"
"github.com/go-logr/logr"
Expand All @@ -31,64 +29,13 @@ const (
func validate( //nolint:funlen,gocyclo
r io.Reader, charset string,
log logr.Logger,
def *editorconfig.Definition,
def *definition,
) []error {
indentSize, _ := strconv.Atoi(def.IndentSize)

var lastLine []byte

var lastIndex int

errs := make([]error, 0)

var insideBlockComment bool

var blockCommentStart []byte

var blockComment []byte

var blockCommentEnd []byte

if def.IndentStyle != "" && def.IndentStyle != UnsetValue {
bs, ok := def.Raw["block_comment_start"]
if ok && bs != "" && bs != UnsetValue {
blockCommentStart = []byte(bs)
bc, ok := def.Raw["block_comment"]

if ok && bc != "" && bs != UnsetValue {
blockComment = []byte(bc)
}

be, ok := def.Raw["block_comment_end"]
if !ok || be == "" || be == UnsetValue {
errs = append(errs, fmt.Errorf("block_comment_end was expected, none were found"))
}

blockCommentEnd = []byte(be)
}
}

maxLength := 0
tabWidth := def.TabWidth

if mll, ok := def.Raw["max_line_length"]; ok && mll != "off" && mll != UnsetValue {
ml, err := strconv.Atoi(mll)
if err != nil || ml < 0 {
errs = append(errs, fmt.Errorf("max_line_length expected a non-negative number, got %q", mll))
}

maxLength = ml

if tabWidth <= 0 {
tabWidth = DefaultTabWidth
}
}

if len(errs) > 0 {
return errs
}

errs = ReadLines(r, func(index int, data []byte) error {
errs := ReadLines(r, func(index int, data []byte) error {
var err error

// The last line may not have the expected ending.
Expand All @@ -109,29 +56,29 @@ func validate( //nolint:funlen,gocyclo
lastLine = data
lastIndex = index

if def.IndentStyle != "" && def.IndentStyle != UnsetValue && def.IndentSize != UnsetValue {
if insideBlockComment && blockCommentEnd != nil {
insideBlockComment = !isBlockCommentEnd(blockCommentEnd, data)
if def.IndentStyle != "" && def.IndentStyle != UnsetValue && def.Definition.IndentSize != UnsetValue {
if def.InsideBlockComment && def.BlockCommentEnd != nil {
def.InsideBlockComment = !isBlockCommentEnd(def.BlockCommentEnd, data)
}

err = indentStyle(def.IndentStyle, indentSize, data)
if err != nil && insideBlockComment && blockComment != nil {
err = indentStyle(def.IndentStyle, def.IndentSize, data)
if err != nil && def.InsideBlockComment && def.BlockComment != nil {
// The indentation may fail within a block comment.
if ve, ok := err.(ValidationError); ok {
err = checkBlockComment(ve.Position, blockComment, data)
err = checkBlockComment(ve.Position, def.BlockComment, data)
}
}

if err == nil && !insideBlockComment && blockCommentStart != nil {
insideBlockComment = isBlockCommentStart(blockCommentStart, data)
if err == nil && !def.InsideBlockComment && def.BlockCommentStart != nil {
def.InsideBlockComment = isBlockCommentStart(def.BlockCommentStart, data)
}
}

if err == nil && def.TrimTrailingWhitespace != nil && *def.TrimTrailingWhitespace {
err = trimTrailingWhitespace(data)
}

if err == nil && maxLength > 0 {
if err == nil && def.MaxLength > 0 {
// Remove any BOM from the first line.
d := data
if index == 0 && charset != "" {
Expand All @@ -142,7 +89,7 @@ func validate( //nolint:funlen,gocyclo
}
}
}
err = MaxLineLength(maxLength, tabWidth, d)
err = MaxLineLength(def.MaxLength, def.TabWidth, d)
}

// Enrich the error with the line number
Expand Down Expand Up @@ -196,39 +143,6 @@ func validate( //nolint:funlen,gocyclo
return errs
}

func overrideUsingPrefix(def *editorconfig.Definition, prefix string) error {
for k, v := range def.Raw {
if strings.HasPrefix(k, prefix) {
nk := k[len(prefix):]
def.Raw[nk] = v

switch nk {
case "indent_style":
def.IndentStyle = v
case "indent_size":
def.IndentSize = v
case "charset":
def.Charset = v
case "end_of_line":
def.EndOfLine = v
case "tab_width":
i, err := strconv.Atoi(v)
if err != nil {
return fmt.Errorf("tab_width cannot be set. %w", err)
}

def.TabWidth = i
case "trim_trailing_whitespace":
return fmt.Errorf("%v cannot be overridden yet, pr welcome", nk)
case "insert_final_newline":
return fmt.Errorf("%v cannot be overridden yet, pr welcome", nk)
}
}
}

return nil
}

// Lint does the hard work of validating the given file.
func Lint(filename string, log logr.Logger) []error {
def, err := editorconfig.GetDefinitionForFilename(filename)
Expand All @@ -240,19 +154,19 @@ func Lint(filename string, log logr.Logger) []error {
}

// LintWithDefinition does the hard work of validating the given file.
func LintWithDefinition(def *editorconfig.Definition, filename string, log logr.Logger) []error {
func LintWithDefinition(d *editorconfig.Definition, filename string, log logr.Logger) []error {
def, err := newDefinition(d)
if err != nil {
return []error{err}
}

fp, err := os.Open(filename)
if err != nil {
return []error{fmt.Errorf("cannot open %s. %w", filename, err)}
}

defer fp.Close()

err = overrideUsingPrefix(def, "eclint_")
if err != nil {
return []error{err}
}

r := bufio.NewReader(fp)

ok, err := probeReadable(fp, r)
Expand Down
Loading

0 comments on commit cb207ae

Please sign in to comment.