func sortImports2(fset *token.FileSet, f *ast.File) (fset2 *token.FileSet, f2 *ast.File) { sortImports(fset, f) imps := astutil.Imports(fset, f) var spacesBefore []string // import paths we need spaces before for _, impSection := range imps { // Within each block of contiguous imports, see if any // import lines are in different group numbers. If so, // we'll need to put a space between them so it's // compatible with gofmt. lastGroup := -1 for _, importSpec := range impSection { importPath, _ := strconv.Unquote(importSpec.Path.Value) groupNum := importGroup(importPath) if groupNum != lastGroup && lastGroup != -1 { spacesBefore = append(spacesBefore, importPath) } lastGroup = groupNum } } // So gross. Print out the entire AST, add a space by modifying the bytes, and reparse the whole thing. // Because I don't see an API that'd let me modify (insert a newline) the FileSet directly. // We really need a go/ast v2, which is as friendly to parsing/printing/formatting as current, but // also friendly towards direct AST modification... To avoid all these horrible hacks. out := []byte(gist5639599.SprintAst(fset, f)) if len(spacesBefore) > 0 { out = addImportSpaces(bytes.NewReader(out), spacesBefore) } fset2 = token.NewFileSet() var err error f2, err = parser.ParseFile(fset2, "", out, parser.ParseComments) if err != nil { panic(err) } return }
// WriteMergedPackage writes a merged package, typically coming from ast.MergePackageFiles, to w. // It sorts and de-duplicates imports. // // TODO: Support comments. func WriteMergedPackage(w io.Writer, fset *token.FileSet, merged *ast.File) { switch 3 { case 1: fmt.Fprintln(w, "package "+gist5639599.SprintAst(fset, merged.Name)) fmt.Fprintln(w) fmt.Fprintln(w, `import (`) // TODO: SortImports (ala goimports). for _, importSpec := range merged.Imports { if importSpec.Name != nil && importSpec.Name.Name == "." { continue } fmt.Fprintln(w, "\t"+gist5639599.SprintAst(fset, importSpec)) } fmt.Fprintln(w, `)`) fmt.Fprintln(w) for _, decl := range merged.Decls { if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT { continue } fmt.Fprintln(w, gist5639599.SprintAst(fset, decl)) fmt.Fprintln(w) } case 2: sortDecls(merged) //fmt.Fprintln(w, gist5639599.SprintAst(token.NewFileSet(), merged)) //ast.SortImports(fset, merged) sortImports2(fset, merged) fmt.Fprintln(w, gist5639599.SprintAst(fset, merged)) case 3: sortDecls(merged) // TODO: Clean up this mess... fset2, f2 := sortImports2(token.NewFileSet(), merged) fmt.Fprintln(w, "package "+gist5639599.SprintAst(fset, merged.Name)) for _, decl := range f2.Decls { if x, ok := decl.(*ast.GenDecl); ok && x.Tok == token.IMPORT { fmt.Fprintln(w) fmt.Fprintln(w, gist5639599.SprintAst(fset2, decl)) } } for _, decl := range merged.Decls { if x, ok := decl.(*ast.GenDecl); ok && (x.Tok == token.IMPORT || x.Tok == token.PACKAGE) { continue } fmt.Fprintln(w) fmt.Fprintln(w, gist5639599.SprintAst(fset, decl)) } case 4: sortDecls(merged) src := []byte(gist5639599.SprintAst(fset, merged)) out, err := imports.Process("", src, nil) if err != nil { panic(err) } os.Stdout.Write(out) fmt.Println() } }