feat: simple format file (without actually format)

check go file -> parse ast -> ignore generated
main
sudo pacman -Syu 2022-11-25 01:17:35 +07:00
parent 6b8625be56
commit 27a82681f1
No known key found for this signature in database
GPG Key ID: D6CB5C6C567C47B0
3 changed files with 110 additions and 7 deletions

View File

@ -46,8 +46,9 @@ func (a *action) Run(c *cli.Context) error {
imports.FormatterWithDiff(a.flags.diff), imports.FormatterWithDiff(a.flags.diff),
) )
if err := f.Format(c.Args().Slice()...); err != nil { args := c.Args().Slice()
return fmt.Errorf("imports formatter: failed to format %v: %w", c.Args().Slice(), err) if err := f.Format(args...); err != nil {
return fmt.Errorf("imports formatter: failed to format %v: %w", args, err)
} }
return nil return nil

37
internal/imports/check.go Normal file
View File

@ -0,0 +1,37 @@
package imports
import (
"go/ast"
"regexp"
"strings"
)
var reGoGenerated = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`)
// Copy from https://github.com/mvdan/gofumpt
func isGoFile(name string) bool {
// Hidden files are ignored
if strings.HasPrefix(name, ".") {
return false
}
return strings.HasSuffix(name, ".go")
}
// Copy from https://github.com/mvdan/gofumpt
func isGoGenerated(file *ast.File) bool {
for _, cg := range file.Comments {
// Ignore if package ... is on top
if cg.Pos() > file.Package {
return false
}
for _, line := range cg.List {
if reGoGenerated.MatchString(line.Text) {
return true
}
}
}
return false
}

View File

@ -1,5 +1,16 @@
package imports package imports
import (
"errors"
"fmt"
"go/parser"
"go/token"
"os"
"path/filepath"
)
var ErrEmptyPaths = errors.New("empty paths")
type Formatter struct { type Formatter struct {
isList bool isList bool
isWrite bool isWrite bool
@ -7,16 +18,70 @@ type Formatter struct {
} }
func NewFormmater(opts ...FormatterOptionFn) *Formatter { func NewFormmater(opts ...FormatterOptionFn) *Formatter {
f := &Formatter{} ft := &Formatter{}
for _, opt := range opts { for _, opt := range opts {
opt(f) opt(ft)
} }
return f return ft
}
// Accept a list of files or directories
func (ft *Formatter) Format(paths ...string) error {
if len(paths) == 0 {
return ErrEmptyPaths
}
// Logic switch case copy from goimports, gofumpt
for _, path := range paths {
switch dir, err := os.Stat(path); {
case err != nil:
return fmt.Errorf("os: failed to stat: [%s] %w", path, err)
case dir.IsDir():
if err := ft.formatDir(path); err != nil {
return err
}
default:
if err := ft.formatFile(path); err != nil {
return err
}
}
}
return nil
}
func (ft *Formatter) formatDir(path string) error {
return nil
}
func (ft *Formatter) formatFile(path string) error {
// Check go file
if !isGoFile(filepath.Base(path)) {
return nil
}
pathBytes, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("os: failed to read file: [%s] %w", path, err)
}
// Parse ast
fset := token.NewFileSet()
parserMode := parser.Mode(0)
parserMode |= parser.ParseComments
pathASTFile, err := parser.ParseFile(fset, path, pathBytes, parserMode)
if err != nil {
return fmt.Errorf("parser: failed to parse file [%s]: %w", path, err)
}
// Ignore generated file
if isGoGenerated(pathASTFile) {
return nil
} }
// Accept a list of files or directories aka fsNames
func (f *Formatter) Format(fsNames ...string) error {
return nil return nil
} }