Skip to content

Commit 7f5af7c

Browse files
committed
Merge pull request #31 from gopherjs/goimports
playground: Add ability to fix imports via goimports.
2 parents 0bd6304 + dbe1134 commit 7f5af7c

File tree

11 files changed

+5649
-39
lines changed

11 files changed

+5649
-39
lines changed

‎playground/index.html‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<spanid="controls">
1313
<inputtype="button" value="Run" ng-click="run(false)" />
1414
<inputtype="button" value="Format" ng-click="format()" />
15+
<labeltitle="Rewrite imports on Format">
16+
<inputng-model="imports" type="checkbox" />Imports
17+
</label>
1518
<inputtype="button" value="Share" ng-click="share()" />
1619
<inputtype="text" class="show-share-url-{{showShareUrl}}" id="share-url" value="{{shareUrl}}" onfocus="select()" />
1720
</span>

‎playground/internal/imports/fix.go‎

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright 2013 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package imports
6+
7+
import (
8+
"go/ast"
9+
"go/token"
10+
"path"
11+
"strings"
12+
13+
"golang.org/x/tools/go/ast/astutil"
14+
)
15+
16+
// importToGroup is a list of functions which map from an import path to
17+
// a group number.
18+
varimportToGroup= []func(importPathstring) (numint, okbool){
19+
func(importPathstring) (numint, okbool){
20+
ifstrings.HasPrefix(importPath, "appengine"){
21+
return2, true
22+
}
23+
return
24+
},
25+
func(importPathstring) (numint, okbool){
26+
ifstrings.Contains(importPath, "."){
27+
return1, true
28+
}
29+
return
30+
},
31+
}
32+
33+
funcimportGroup(importPathstring) int{
34+
for_, fn:=rangeimportToGroup{
35+
ifn, ok:=fn(importPath); ok{
36+
returnn
37+
}
38+
}
39+
return0
40+
}
41+
42+
funcfixImports(fset*token.FileSet, f*ast.File) (added []string, errerror){
43+
// refs are a set of possible package references currently unsatisfied by imports.
44+
// first key: either base package (e.g. "fmt") or renamed package
45+
// second key: referenced package symbol (e.g. "Println")
46+
refs:=make(map[string]map[string]bool)
47+
48+
// decls are the current package imports. key is base package or renamed package.
49+
decls:=make(map[string]*ast.ImportSpec)
50+
51+
// collect potential uses of packages.
52+
varvisitorvisitFn
53+
visitor=visitFn(func(node ast.Node) ast.Visitor{
54+
ifnode==nil{
55+
returnvisitor
56+
}
57+
switchv:=node.(type){
58+
case*ast.ImportSpec:
59+
ifv.Name!=nil{
60+
decls[v.Name.Name] =v
61+
} else{
62+
local:=importPathToName(strings.Trim(v.Path.Value, `\"`))
63+
decls[local] =v
64+
}
65+
case*ast.SelectorExpr:
66+
xident, ok:=v.X.(*ast.Ident)
67+
if!ok{
68+
break
69+
}
70+
ifxident.Obj!=nil{
71+
// if the parser can resolve it, it's not a package ref
72+
break
73+
}
74+
pkgName:=xident.Name
75+
ifrefs[pkgName] ==nil{
76+
refs[pkgName] =make(map[string]bool)
77+
}
78+
ifdecls[pkgName] ==nil{
79+
refs[pkgName][v.Sel.Name] =true
80+
}
81+
}
82+
returnvisitor
83+
})
84+
ast.Walk(visitor, f)
85+
86+
// Nil out any unused ImportSpecs, to be removed in following passes
87+
unusedImport:=map[string]bool{}
88+
forpkg, is:=rangedecls{
89+
ifrefs[pkg] ==nil&&pkg!="_"&&pkg!="."{
90+
unusedImport[strings.Trim(is.Path.Value, `"`)] =true
91+
}
92+
}
93+
foripath:=rangeunusedImport{
94+
ifipath=="C"{
95+
// Don't remove cgo stuff.
96+
continue
97+
}
98+
astutil.DeleteImport(fset, f, ipath)
99+
}
100+
101+
// Search for imports matching potential package references.
102+
searches:=0
103+
typeresultstruct{
104+
ipathstring
105+
namestring
106+
errerror
107+
}
108+
results:=make(chanresult)
109+
forpkgName, symbols:=rangerefs{
110+
iflen(symbols) ==0{
111+
continue// skip over packages already imported
112+
}
113+
gofunc(pkgNamestring, symbolsmap[string]bool){
114+
ipath, rename, err:=findImport(pkgName, symbols)
115+
r:=result{ipath: ipath, err: err}
116+
ifrename{
117+
r.name=pkgName
118+
}
119+
results<-r
120+
}(pkgName, symbols)
121+
searches++
122+
}
123+
fori:=0; i<searches; i++{
124+
result:=<-results
125+
ifresult.err!=nil{
126+
returnnil, result.err
127+
}
128+
ifresult.ipath!=""{
129+
ifresult.name!=""{
130+
astutil.AddNamedImport(fset, f, result.name, result.ipath)
131+
} else{
132+
astutil.AddImport(fset, f, result.ipath)
133+
}
134+
added=append(added, result.ipath)
135+
}
136+
}
137+
138+
returnadded, nil
139+
}
140+
141+
// importPathToName returns the package name for the given import path.
142+
varimportPathToName=importPathToNameBasic
143+
144+
// importPathToNameBasic assumes the package name is the base of import path.
145+
funcimportPathToNameBasic(importPathstring) (packageNamestring){
146+
returnpath.Base(importPath)
147+
}
148+
149+
typepkgstruct{
150+
importpathstring// full pkg import path, e.g. "net/http"
151+
dirstring// absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
152+
}
153+
154+
// findImport searches for a package with the given symbols.
155+
// If no package is found, findImport returns "".
156+
// Declared as a variable rather than a function so goimports can be easily
157+
// extended by adding a file with an init function.
158+
varfindImport=findImportStdlib
159+
160+
typevisitFnfunc(node ast.Node) ast.Visitor
161+
162+
func (fnvisitFn) Visit(node ast.Node) ast.Visitor{
163+
returnfn(node)
164+
}
165+
166+
funcfindImportStdlib(shortPkgstring, symbolsmap[string]bool) (importPathstring, renamebool, errerror){
167+
forsymbol:=rangesymbols{
168+
path:=stdlib[shortPkg+"."+symbol]
169+
ifpath==""{
170+
return"", false, nil
171+
}
172+
ifimportPath!=""&&importPath!=path{
173+
// Ambiguous. Symbols pointed to different things.
174+
return"", false, nil
175+
}
176+
importPath=path
177+
}
178+
returnimportPath, false, nil
179+
}

‎playground/internal/imports/gen.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//go:generate go run mkapi.go -output=gopherjs.txt -gopath github.com/gopherjs/gopherjs/js
2+
//go:generate go run mkstdlib.go -output=zstdlib
3+
//go:generate rm gopherjs.txt
4+
5+
package imports

0 commit comments

Comments
(0)