-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from jdeflander/feature/15-initial-release
Setup initial release
- Loading branch information
Showing
32 changed files
with
1,928 additions
and
283 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
jobs: | ||
checkout: | ||
runs-on: ubuntu-18.04 | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/upload-artifact@v2 | ||
with: | ||
name: src | ||
path: . | ||
lint: | ||
needs: checkout | ||
runs-on: ubuntu-18.04 | ||
steps: | ||
- uses: actions/download-artifact@v2 | ||
with: | ||
name: src | ||
- run: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.26.0 | ||
- run: bin/golangci-lint run | ||
test: | ||
needs: checkout | ||
runs-on: ubuntu-18.04 | ||
steps: | ||
- uses: actions/download-artifact@v2 | ||
with: | ||
name: src | ||
- uses: actions/setup-go@v2 | ||
with: | ||
go-version: "1.13" | ||
- run: go test -v ./... | ||
name: main | ||
on: | ||
pull_request: | ||
branches: | ||
- master |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
issues: | ||
exclude-use-default: false | ||
|
||
linters: | ||
enable: | ||
- goimports | ||
- golint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
module github.com/jdeflander/goarrange | ||
|
||
go 1.13 | ||
|
||
require github.com/google/go-cmp v0.4.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= | ||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package arranger | ||
|
||
import ( | ||
"go/ast" | ||
"go/token" | ||
|
||
"github.com/jdeflander/goarrange/internal/arranger/internal/index" | ||
) | ||
|
||
// Arranger represents a source code arranger for go packages. | ||
type Arranger struct { | ||
index index.Index | ||
set *token.FileSet | ||
} | ||
|
||
// New creates a new arranger for the given package and file set. | ||
// | ||
// The given package must have been parsed with the given file set. | ||
func New(pkg *ast.Package, set *token.FileSet) Arranger { | ||
idx := index.New(pkg) | ||
return Arranger{ | ||
index: idx, | ||
set: set, | ||
} | ||
} | ||
|
||
// Arrange arranges the given file with the given arranger. | ||
// | ||
// The given file must be part of the given arranger's package, and its contents should be represented by the given | ||
// bytes. This method returns an arranged copy of the given contents. | ||
func (a Arranger) Arrange(file *ast.File, src []byte) []byte { | ||
indexes := a.index.Sort(file.Decls) | ||
size := len(src) | ||
dst := make([]byte, size) | ||
dstOffset := 0 | ||
mp := ast.NewCommentMap(a.set, file, file.Comments) | ||
srcOffset := 0 | ||
|
||
for dstIndex, srcIndex := range indexes { | ||
dstPrefix := dst[dstOffset:] | ||
dstStart, dstEnd := bounds(file.Decls, dstIndex, mp, a.set) | ||
srcPrefix := src[srcOffset:dstStart] | ||
dstOffset += copy(dstPrefix, srcPrefix) | ||
|
||
dstInfix := dst[dstOffset:] | ||
srcStart, srcEnd := bounds(file.Decls, srcIndex, mp, a.set) | ||
srcInfix := src[srcStart:srcEnd] | ||
dstOffset += copy(dstInfix, srcInfix) | ||
|
||
srcOffset = dstEnd | ||
} | ||
|
||
dstSuffix := dst[dstOffset:] | ||
srcSuffix := src[srcOffset:] | ||
copy(dstSuffix, srcSuffix) | ||
return dst | ||
} | ||
|
||
// Arranged checks whether the given file is arranged according to the given arranger. | ||
// | ||
// The given file must be part of the given arranger's package. | ||
func (a Arranger) Arranged(file *ast.File) bool { | ||
return a.index.Sorted(file.Decls) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package arranger_test | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"go/parser" | ||
"go/token" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/jdeflander/goarrange/internal/arranger" | ||
) | ||
|
||
func TestArranger(t *testing.T) { | ||
if err := filepath.Walk("testdata", walk); err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
|
||
func notGolden(info os.FileInfo) bool { | ||
name := info.Name() | ||
return !strings.HasSuffix(name, ".golden.go") | ||
} | ||
|
||
func walk(path string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return fmt.Errorf("failed walking to file at '%s': %w", path, err) | ||
} | ||
if !info.IsDir() { | ||
return nil | ||
} | ||
|
||
set := token.NewFileSet() | ||
packages, err := parser.ParseDir(set, path, notGolden, parser.ParseComments) | ||
if err != nil { | ||
return fmt.Errorf("failed parsing directory at '%s': %v", path, err) | ||
} | ||
|
||
for _, pkg := range packages { | ||
a := arranger.New(pkg, set) | ||
for name, file := range pkg.Files { | ||
bs, err := ioutil.ReadFile(name) | ||
if err != nil { | ||
return fmt.Errorf("failed reading file at '%s': %v", name, err) | ||
} | ||
gotArrange := a.Arrange(file, bs) | ||
golden := fmt.Sprintf("%slden.go", name) | ||
wantArrange, err := ioutil.ReadFile(golden) | ||
if err != nil { | ||
return fmt.Errorf("failed reading golden file at '%s': %v", golden, err) | ||
} | ||
if diff := cmp.Diff(gotArrange, wantArrange); diff != "" { | ||
return fmt.Errorf("arrange output mismatch for file at '%s':\n%s", name, diff) | ||
} | ||
|
||
gotArranged := a.Arranged(file) | ||
wantArranged := bytes.Equal(bs, gotArrange) | ||
if diff := cmp.Diff(gotArranged, wantArranged); diff != "" { | ||
return fmt.Errorf("arranged output mismatch for file at '%s':\n%s", name, diff) | ||
} | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package index | ||
|
||
import ( | ||
"go/ast" | ||
"go/doc" | ||
"sort" | ||
) | ||
|
||
// Index represents an index of a Go package's arrangeable declarations. | ||
type Index struct { | ||
decls map[ast.Decl]int | ||
} | ||
|
||
// New returns an index for the given Go package. | ||
func New(pkg *ast.Package) Index { | ||
decls := map[ast.Decl]int{} | ||
idx := Index{decls: decls} | ||
p := doc.New(pkg, "", doc.AllDecls|doc.PreserveAST) | ||
|
||
idx.appendValues(p.Consts) | ||
idx.appendValues(p.Vars) | ||
idx.appendFuncs(p.Funcs) | ||
|
||
for _, typ := range p.Types { | ||
idx.append(typ.Decl) | ||
idx.appendValues(typ.Consts) | ||
idx.appendValues(typ.Vars) | ||
idx.appendFuncs(typ.Funcs) | ||
idx.appendFuncs(typ.Methods) | ||
} | ||
return idx | ||
} | ||
|
||
// Sort returns the indices of the given declarations, sorted according to the given index. | ||
func (i Index) Sort(decls []ast.Decl) []int { | ||
records := i.records(decls) | ||
sort.Stable(records) | ||
|
||
var indexes []int | ||
for _, record := range records { | ||
indexes = append(indexes, record.index) | ||
} | ||
return indexes | ||
} | ||
|
||
// Sorted checks whether the given declarations are sorted according to the given index. | ||
func (i Index) Sorted(decls []ast.Decl) bool { | ||
records := i.records(decls) | ||
return sort.IsSorted(records) | ||
} | ||
|
||
func (i Index) append(decl ast.Decl) { | ||
i.decls[decl] = len(i.decls) | ||
} | ||
|
||
func (i Index) appendFuncs(funcs []*doc.Func) { | ||
for _, fun := range funcs { | ||
i.append(fun.Decl) | ||
} | ||
} | ||
|
||
func (i Index) appendValues(values []*doc.Value) { | ||
for _, value := range values { | ||
i.append(value.Decl) | ||
} | ||
} | ||
|
||
func (i Index) records(decls []ast.Decl) records { | ||
var records records | ||
for index, decl := range decls { | ||
key, ok := i.decls[decl] | ||
record := record{ | ||
index: index, | ||
key: key, | ||
ok: ok, | ||
} | ||
records = append(records, record) | ||
} | ||
return records | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package index_test | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"go/parser" | ||
"go/token" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/jdeflander/goarrange/internal/arranger/internal/index" | ||
) | ||
|
||
func TestIndex(t *testing.T) { | ||
if err := filepath.Walk("testdata", walk); err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
|
||
func walk(path string, info os.FileInfo, err error) error { | ||
if err != nil { | ||
return fmt.Errorf("failed walking to file at '%s': %w", path, err) | ||
} | ||
if !info.IsDir() { | ||
return nil | ||
} | ||
|
||
set := token.NewFileSet() | ||
packages, err := parser.ParseDir(set, path, nil, 0) | ||
if err != nil { | ||
return fmt.Errorf("failed parsing directory at '%s': %v", path, err) | ||
} | ||
|
||
for _, pkg := range packages { | ||
idx := index.New(pkg) | ||
for name, file := range pkg.Files { | ||
gotSort := idx.Sort(file.Decls) | ||
golden := fmt.Sprintf("%slden.json", name) | ||
bytes, err := ioutil.ReadFile(golden) | ||
if err != nil { | ||
return fmt.Errorf("failed reading golden file at '%s': %v", golden, err) | ||
} | ||
var wantSort []int | ||
if err := json.Unmarshal(bytes, &wantSort); err != nil { | ||
return fmt.Errorf("failed unmarshalling golden file at '%s': %v", golden, err) | ||
} | ||
if diff := cmp.Diff(gotSort, wantSort); diff != "" { | ||
return fmt.Errorf("sort mismatch for file at '%s' (-got +want):\n%s", name, diff) | ||
} | ||
|
||
gotSorted := idx.Sorted(file.Decls) | ||
wantSorted := sort.IntsAreSorted(wantSort) | ||
if diff := cmp.Diff(gotSorted, wantSorted); diff != "" { | ||
return fmt.Errorf("sorted mismatch for file at '%s' (-got +want):\n%s", name, diff) | ||
} | ||
} | ||
} | ||
return nil | ||
} |
File renamed without changes.
Oops, something went wrong.