{"id":13612955,"url":"https://github.com/dave/dst","last_synced_at":"2025-10-16T13:11:22.201Z","repository":{"id":37664141,"uuid":"148895273","full_name":"dave/dst","owner":"dave","description":"Decorated Syntax Tree - manipulate Go source with perfect fidelity.","archived":false,"fork":false,"pushed_at":"2023-10-15T04:13:28.000Z","size":889,"stargazers_count":1355,"open_issues_count":11,"forks_count":59,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-11T02:51:33.634Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-09-15T11:16:29.000Z","updated_at":"2025-04-09T00:48:23.000Z","dependencies_parsed_at":"2024-01-13T23:10:39.558Z","dependency_job_id":"bb0b9e6c-dbca-44d9-9b01-d40d6135883c","html_url":"https://github.com/dave/dst","commit_stats":{"total_commits":197,"total_committers":5,"mean_commits":39.4,"dds":"0.030456852791878153","last_synced_commit":"5fa8d6ebe49a6b04afa15ee8f982d210f8a00b80"},"previous_names":[],"tags_count":60,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fdst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fdst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fdst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fdst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dave","download_url":"https://codeload.github.com/dave/dst/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254092776,"owners_count":22013290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T20:00:37.153Z","updated_at":"2025-10-16T13:11:17.146Z","avatar_url":"https://github.com/dave.png","language":"Go","funding_links":[],"categories":["开源类库","Open source library","Go"],"sub_categories":["解释器","Interpreter"],"readme":"[![Build Status](https://travis-ci.org/dave/dst.svg?branch=master)](https://travis-ci.org/dave/dst)\n[![Documentation](https://img.shields.io/badge/godoc-documentation-brightgreen.svg)](https://godoc.org/github.com/dave/dst/decorator)\n[![codecov](https://img.shields.io/badge/codecov-92%25-brightgreen.svg)](https://codecov.io/gh/dave/dst)\n![stability-stable](https://img.shields.io/badge/stability-stable-brightgreen.svg)\n[![Sourcegraph](https://sourcegraph.com/github.com/dave/dst/-/badge.svg)](https://sourcegraph.com/github.com/dave/dst?badge)\n\n# Decorated Syntax Tree\n\nThe `dst` package enables manipulation of a Go syntax tree with high fidelity. Decorations (e.g. \ncomments and line spacing) remain attached to the correct nodes as the tree is modified.\n\n## Where does `go/ast` break?\n\nThe `go/ast` package wasn't created with source manipulation as an intended use-case. Comments are \nstored by their byte offset instead of attached to nodes, so re-arranging nodes breaks the output. \nSee [this Go issue](https://github.com/golang/go/issues/20744) for more information.\n\nConsider this example where we want to reverse the order of the two statements. As you can see the \ncomments don't remain attached to the correct nodes:\n\n```go\ncode := `package a\n\nfunc main(){\n\tvar a int    // foo\n\tvar b string // bar\n}\n`\nfset := token.NewFileSet()\nf, err := parser.ParseFile(fset, \"\", code, parser.ParseComments)\nif err != nil {\n\tpanic(err)\n}\n\nlist := f.Decls[0].(*ast.FuncDecl).Body.List\nlist[0], list[1] = list[1], list[0]\n\nif err := format.Node(os.Stdout, fset, f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package a\n//\n//func main() {\n//\t// foo\n//\tvar b string\n//\tvar a int\n//\t// bar\n//}\n```\n\nHere's the same example using `dst`:\n\n```go\ncode := `package a\n\nfunc main(){\n\tvar a int    // foo\n\tvar b string // bar\n}\n`\nf, err := decorator.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\nlist := f.Decls[0].(*dst.FuncDecl).Body.List\nlist[0], list[1] = list[1], list[0]\n\nif err := decorator.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package a\n//\n//func main() {\n//\tvar b string // bar\n//\tvar a int    // foo\n//}\n```\n\n## Usage\n\nParsing a source file to `dst` and printing the results after modification can be accomplished with \nseveral `Parse` and `Print` convenience functions in the [decorator](https://godoc.org/github.com/dave/dst/decorator) \npackage. \n\nFor more fine-grained control you can use [Decorator](https://godoc.org/github.com/dave/dst/decorator#Decorator) \nto convert from `ast` to `dst`, and [Restorer](https://godoc.org/github.com/dave/dst/decorator#Restorer) \nto convert back again. \n\n### Comments\n\nComments are added at decoration attachment points. [See here](https://github.com/dave/dst/blob/master/decorations-types-generated.go) \nfor a full list of these points, along with demonstration code of where they are rendered in the \noutput.\n\nThe decoration attachment points have convenience functions `Append`, `Prepend`, `Replace`, `Clear` \nand `All` to accomplish common tasks. Use the full text of your comment including the `//` or `/**/` \nmarkers. When adding a line comment, a newline is automatically rendered.\n\n```go\ncode := `package main\n\nfunc main() {\n\tprintln(\"Hello World!\")\n}`\nf, err := decorator.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\ncall := f.Decls[0].(*dst.FuncDecl).Body.List[0].(*dst.ExprStmt).X.(*dst.CallExpr)\n\ncall.Decs.Start.Append(\"// you can add comments at the start...\")\ncall.Decs.Fun.Append(\"/* ...in the middle... */\")\ncall.Decs.End.Append(\"// or at the end.\")\n\nif err := decorator.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//func main() {\n//\t// you can add comments at the start...\n//\tprintln /* ...in the middle... */ (\"Hello World!\") // or at the end.\n//}\n```\n\n### Spacing\n\nThe `Before` property marks the node as having a line space (new line or empty line) before the node. \nThese spaces are rendered before any decorations attached to the `Start` decoration point. The `After`\nproperty is similar but rendered after the node (and after any `End` decorations).\n\n```go\ncode := `package main\n\nfunc main() {\n\tprintln(a, b, c)\n}`\nf, err := decorator.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\ncall := f.Decls[0].(*dst.FuncDecl).Body.List[0].(*dst.ExprStmt).X.(*dst.CallExpr)\n\ncall.Decs.Before = dst.EmptyLine\ncall.Decs.After = dst.EmptyLine\n\nfor _, v := range call.Args {\n\tv := v.(*dst.Ident)\n\tv.Decs.Before = dst.NewLine\n\tv.Decs.After = dst.NewLine\n}\n\nif err := decorator.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//func main() {\n//\n//\tprintln(\n//\t\ta,\n//\t\tb,\n//\t\tc,\n//\t)\n//\n//}\n```\n\n### Decorations\n\nThe common decoration properties (`Start`, `End`, `Before` and `After`) occur on all nodes, and can be \naccessed with the `Decorations()` method on the `Node` interface:\n\n```go\ncode := `package main\n\nfunc main() {\n\tvar i int\n\ti++\n\tprintln(i)\n}`\nf, err := decorator.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\nlist := f.Decls[0].(*dst.FuncDecl).Body.List\n\nlist[0].Decorations().Before = dst.EmptyLine\nlist[0].Decorations().End.Append(\"// the Decorations method allows access to the common\")\nlist[1].Decorations().End.Append(\"// decoration properties (Before, Start, End and After)\")\nlist[2].Decorations().End.Append(\"// for all nodes.\")\nlist[2].Decorations().After = dst.EmptyLine\n\nif err := decorator.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//func main() {\n//\n//\tvar i int  // the Decorations method allows access to the common\n//\ti++        // decoration properties (Before, Start, End and After)\n//\tprintln(i) // for all nodes.\n//\n//}\n```\n\n#### dstutil.Decorations\n\nWhile debugging, it is often useful to have a list of all decorations attached to a node. The\n[dstutil](https://github.com/dave/dst/tree/master/dstutil) package provides a helper function `Decorations` which\nreturns a list of the attachment points and all decorations for any node:\n\n```go\ncode := `package main\n\n// main comment\n// is multi line\nfunc main() {\n\n\tif true {\n\n\t\t// foo\n\t\tprintln( /* foo inline */ \"foo\")\n\t} else if false {\n\t\tprintln /* bar inline */ (\"bar\")\n\n\t\t// bar after\n\n\t} else {\n\t\t// empty block\n\t}\n}`\n\nf, err := decorator.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\ndst.Inspect(f, func(node dst.Node) bool {\n\tif node == nil {\n\t\treturn false\n\t}\n\tbefore, after, points := dstutil.Decorations(node)\n\tvar info string\n\tif before != dst.None {\n\t\tinfo += fmt.Sprintf(\"- Before: %s\\n\", before)\n\t}\n\tfor _, point := range points {\n\t\tif len(point.Decs) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tinfo += fmt.Sprintf(\"- %s: [\", point.Name)\n\t\tfor i, dec := range point.Decs {\n\t\t\tif i \u003e 0 {\n\t\t\t\tinfo += \", \"\n\t\t\t}\n\t\t\tinfo += fmt.Sprintf(\"%q\", dec)\n\t\t}\n\t\tinfo += \"]\\n\"\n\t}\n\tif after != dst.None {\n\t\tinfo += fmt.Sprintf(\"- After: %s\\n\", after)\n\t}\n\tif info != \"\" {\n\t\tfmt.Printf(\"%T\\n%s\\n\", node, info)\n\t}\n\treturn true\n})\n\n//Output:\n//*dst.FuncDecl\n//- Before: NewLine\n//- Start: [\"// main comment\", \"// is multi line\"]\n//\n//*dst.IfStmt\n//- Before: NewLine\n//- After: NewLine\n//\n//*dst.ExprStmt\n//- Before: NewLine\n//- Start: [\"// foo\"]\n//- After: NewLine\n//\n//*dst.CallExpr\n//- Lparen: [\"/* foo inline */\"]\n//\n//*dst.ExprStmt\n//- Before: NewLine\n//- End: [\"\\n\", \"\\n\", \"// bar after\"]\n//- After: NewLine\n//\n//*dst.CallExpr\n//- Fun: [\"/* bar inline */\"]\n//\n//*dst.BlockStmt\n//- Lbrace: [\"\\n\", \"// empty block\"]\n```\n\n### Newlines\n\nThe `Before` and `After` properties cover the majority of cases, but occasionally a newline needs to \nbe rendered inside a node. Simply add a `\\n` decoration to accomplish this. \n\n### Clone\n\nRe-using an existing node elsewhere in the tree will panic when the tree is restored to `ast`. Instead,\nuse the `Clone` function to make a deep copy of the node before re-use:\n\n```go\ncode := `package main\n\nvar i /* a */ int`\n\nf, err := decorator.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\ncloned := dst.Clone(f.Decls[0]).(*dst.GenDecl)\n\ncloned.Decs.Before = dst.NewLine\ncloned.Specs[0].(*dst.ValueSpec).Names[0].Name = \"j\"\ncloned.Specs[0].(*dst.ValueSpec).Names[0].Decs.End.Replace(\"/* b */\")\n\nf.Decls = append(f.Decls, cloned)\n\nif err := decorator.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//var i /* a */ int\n//var j /* b */ int\n```\n\n### Apply\n\nThe [dstutil](https://github.com/dave/dst/tree/master/dstutil) package is a fork of `golang.org/x/tools/go/ast/astutil`, \nand provides the `Apply` function with similar semantics.     \n\n### Imports\n\nThe decorator can automatically manage the `import` block, which is a non-trivial task.\n\nUse [NewDecoratorWithImports](https://godoc.org/github.com/dave/dst/decorator#NewDecoratorWithImports) \nand [NewRestorerWithImports](https://godoc.org/github.com/dave/dst/decorator#NewRestorerWithImports) \nto create an import aware decorator / restorer. \n\nDuring decoration, remote identifiers are normalised - `*ast.SelectorExpr` nodes that represent \nqualified identifiers are replaced with `*dst.Ident` nodes with the `Path` field set to the path of \nthe imported package. \n\nWhen adding a qualified identifier node, there is no need to use `*dst.SelectorExpr` - just add a \n`*dst.Ident` and set `Path` to the imported package path. The restorer will wrap it in a \n`*ast.SelectorExpr` where appropriate when converting back to ast, and also update the import \nblock.\n\nTo enable import management, the decorator must be able to resolve the imported package for \nselector expressions and identifiers, and the restorer must be able to resolve the name of a \npackage given it's path. Several implementations for these resolvers are provided, and the best \nmethod will depend on the environment. [See below](#resolvers) for more details.\n\n### Load\n\nThe [Load](https://godoc.org/github.com/dave/dst/decorator#Load) convenience function uses \n`go/packages` to load packages and decorate all loaded ast files, with import management enabled:\n\n```go\n// Create a simple module in a temporary directory\ndir, err := tempDir(map[string]string{\n\t\"go.mod\":\t\"module root\",\n\t\"main.go\":\t\"package main \\n\\n func main() {}\",\n})\ndefer os.RemoveAll(dir)\nif err != nil {\n\tpanic(err)\n}\n\n// Use the Load convenience function that calls go/packages to load the package. All loaded\n// ast files are decorated to dst.\npkgs, err := decorator.Load(\u0026packages.Config{Dir: dir, Mode: packages.LoadSyntax}, \"root\")\nif err != nil {\n\tpanic(err)\n}\np := pkgs[0]\nf := p.Syntax[0]\n\n// Add a call expression. Note we don't have to use a SelectorExpr - just adding an Ident with\n// the imported package path will do. The restorer will add SelectorExpr where appropriate when\n// converting back to ast. Note the new Path field on *dst.Ident. Set this to the package path\n// of the imported package, and the restorer will automatically add the import to the import\n// block.\nb := f.Decls[0].(*dst.FuncDecl).Body\nb.List = append(b.List, \u0026dst.ExprStmt{\n\tX: \u0026dst.CallExpr{\n\t\tFun:\t\u0026dst.Ident{Path: \"fmt\", Name: \"Println\"},\n\t\tArgs: []dst.Expr{\n\t\t\t\u0026dst.BasicLit{Kind: token.STRING, Value: strconv.Quote(\"Hello, World!\")},\n\t\t},\n\t},\n})\n\n// Create a restorer with the import manager enabled, and print the result. As you can see, the\n// import block is automatically managed, and the Println ident is converted to a SelectorExpr:\nr := decorator.NewRestorerWithImports(\"root\", gopackages.New(dir))\nif err := r.Print(p.Syntax[0]); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//import \"fmt\"\n//\n//func main() { fmt.Println(\"Hello, World!\") }\n```\n\n### Mappings\n\nThe decorator exposes `Dst.Nodes` and `Ast.Nodes` which map between `ast.Node` and `dst.Node`. This \nenables systems that refer to `ast` nodes (such as `go/types`) to be used:\n\n```go\ncode := `package main\n\nfunc main() {\n\tvar i int\n\ti++\n\tprintln(i)\n}`\n\n// Parse the code to AST\nfset := token.NewFileSet()\nastFile, err := parser.ParseFile(fset, \"\", code, parser.ParseComments)\nif err != nil {\n\tpanic(err)\n}\n\n// Invoke the type checker using AST as input\ntypesInfo := types.Info{\n\tDefs:\tmake(map[*ast.Ident]types.Object),\n\tUses:\tmake(map[*ast.Ident]types.Object),\n}\nconf := \u0026types.Config{}\nif _, err := conf.Check(\"\", fset, []*ast.File{astFile}, \u0026typesInfo); err != nil {\n\tpanic(err)\n}\n\n// Create a new decorator, which will track the mapping between ast and dst nodes\ndec := decorator.NewDecorator(fset)\n\n// Decorate the *ast.File to give us a *dst.File\nf, err := dec.DecorateFile(astFile)\nif err != nil {\n\tpanic(err)\n}\n\n// Find the *dst.Ident for the definition of \"i\"\ndstDef := f.Decls[0].(*dst.FuncDecl).Body.List[0].(*dst.DeclStmt).Decl.(*dst.GenDecl).Specs[0].(*dst.ValueSpec).Names[0]\n\n// Find the *ast.Ident using the Ast.Nodes mapping\nastDef := dec.Ast.Nodes[dstDef].(*ast.Ident)\n\n// Find the types.Object corresponding to \"i\"\nobj := typesInfo.Defs[astDef]\n\n// Find all the uses of that object\nvar astUses []*ast.Ident\nfor id, ob := range typesInfo.Uses {\n\tif ob != obj {\n\t\tcontinue\n\t}\n\tastUses = append(astUses, id)\n}\n\n// Find each *dst.Ident in the Dst.Nodes mapping\nvar dstUses []*dst.Ident\nfor _, id := range astUses {\n\tdstUses = append(dstUses, dec.Dst.Nodes[id].(*dst.Ident))\n}\n\n// Change the name of the original definition and all uses\ndstDef.Name = \"foo\"\nfor _, id := range dstUses {\n\tid.Name = \"foo\"\n}\n\n// Print the DST\nif err := decorator.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//func main() {\n//\tvar foo int\n//\tfoo++\n//\tprintln(foo)\n//}\n```\n\n## Resolvers\n\nThere are two separate interfaces defined by the [resolver package](https://github.com/dave/dst/tree/master/decorator/resolver) \nwhich allow the decorator and restorer to automatically manage the imports block.\n\nThe decorator uses a `DecoratorResolver` which resolves the package path of any `*ast.Ident`. This is \ncomplicated by dot-import syntax ([see below](#dot-imports)).\n\nThe restorer uses a `RestorerResolver` which resolves the name of any package given the path. This \nis complicated by vendoring and Go modules.\n\nWhen `Resolver` is set on `Decorator` or `Restorer`, the `Path` property must be set to the local \npackage path.\n\nSeveral implementations of both interfaces that are suitable for different environments are \nprovided:\n\n### DecoratorResolver\n\n#### gotypes\n\nThe [gotypes](https://github.com/dave/dst/blob/master/decorator/resolver/gotypes/resolver.go) \npackage provides a `DecoratorResolver` with full dot-import compatibility. However it requires full \nexport data for all imported packages, so the `Uses` map from `go/types.Info` is required. There \nare several methods of generating `go/types.Info`. Using `golang.org/x/tools/go/packages.Load` is \nrecommended for full Go modules compatibility. See the [decorator.Load](https://godoc.org/github.com/dave/dst/decorator#Load)\nconvenience function to automate this.\n\n#### goast\n\nThe [goast](https://github.com/dave/dst/blob/master/decorator/resolver/goast/resolver.go) package \nprovides a simplified `DecoratorResolver` that only needs to scan a single ast file. This is unable \nto resolve identifiers from dot-imported packages, so will panic if a dot-import is encountered in \nthe import block. It uses the provided `RestorerResolver` to resolve the names of all imported \npackages. If no `RestorerResolver` is provided, the [guess](#guess-and-simple) implementation is used. \n\n### RestorerResolver\n\n#### gopackages\n\nThe [gopackages](https://github.com/dave/dst/blob/master/decorator/resolver/gopackages/resolver.go) \npackage provides a `RestorerResolver` with full compatibility with Go modules. It uses \n`golang.org/x/tools/go/packages` to load the package data. This may be very slow, and uses the `go` \ncommand line tool to query package data, so may not be compatible with some environments. \n\n#### gobuild\n\nThe [gobuild](https://github.com/dave/dst/blob/master/decorator/resolver/gobuild/resolver.go) \npackage provides an alternative `RestorerResolver` that uses the legacy `go/build` system to load \nthe imported package data. This may be needed in some circumstances and provides better performance \nthan `go/packages`. However, this is not Go modules aware.\n\n#### guess and simple\n\nThe [guess](https://github.com/dave/dst/blob/master/decorator/resolver/guess/resolver.go) and \n[simple](https://github.com/dave/dst/blob/master/decorator/resolver/simple/resolver.go) packages\nprovide simple `RestorerResolver` implementations that may be useful in certain circumstances, or \nwhere performance is critical. `simple` resolves paths only if they occur in a provided map. \n`guess` guesses the package name based on the last part of the path.\n\n### Example\n\nHere's an example of supplying resolvers for the decorator and restorer:\n\n```go\ncode := `package main\n\n\timport \"fmt\"\n\n\tfunc main() {\n\t\tfmt.Println(\"a\")\n\t}`\n\ndec := decorator.NewDecoratorWithImports(token.NewFileSet(), \"main\", goast.New())\n\nf, err := dec.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\nf.Decls[1].(*dst.FuncDecl).Body.List[0].(*dst.ExprStmt).X.(*dst.CallExpr).Args = []dst.Expr{\n\t\u0026dst.CallExpr{\n\t\tFun: \u0026dst.Ident{Name: \"A\", Path: \"foo.bar/baz\"},\n\t},\n}\n\nres := decorator.NewRestorerWithImports(\"main\", guess.New())\nif err := res.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//import (\n//\t\"fmt\"\n//\n//\t\"foo.bar/baz\"\n//)\n//\n//func main() {\n//\tfmt.Println(baz.A())\n//}\n```\n\n### Alias\n\nTo control the alias of imports, use a `FileRestorer`:\n\n```go\ncode := `package main\n\n\timport \"fmt\"\n\n\tfunc main() {\n\t\tfmt.Println(\"a\")\n\t}`\n\ndec := decorator.NewDecoratorWithImports(token.NewFileSet(), \"main\", goast.New())\n\nf, err := dec.Parse(code)\nif err != nil {\n\tpanic(err)\n}\n\nres := decorator.NewRestorerWithImports(\"main\", guess.New())\n\nfr := res.FileRestorer()\nfr.Alias[\"fmt\"] = \"fmt1\"\n\nif err := fr.Print(f); err != nil {\n\tpanic(err)\n}\n\n//Output:\n//package main\n//\n//import fmt1 \"fmt\"\n//\n//func main() {\n//\tfmt1.Println(\"a\")\n//}\n``` \n\n### Details\n\nFor more information on exactly how the imports block is managed, read through the [test \ncases](https://github.com/dave/dst/blob/master/decorator/restorer_resolver_test.go).\n\n### Dot-imports\n\nConsider this file...\n\n```go\npackage main\n\nimport (\n\t. \"a\"\n)\n\nfunc main() {\n\tB()\n\tC()\n}\n```\n\n`B` and `C` could be local identifiers from a different file in this package,\nor from the imported package `a`. If only one is from `a` and it is removed, we should remove the\nimport when we restore to `ast`. Thus the resolver needs to be able to resolve the package using \nthe full info from `go/types`.\n\n## Status\n\nThis package is well tested and used in many projects. The API should be considered stable going forward.\n\n## Chat?\n\nFeel free to create an [issue](https://github.com/dave/dst/issues) or chat in the \n[#dst](https://gophers.slack.com/messages/CCVL24MTQ) Gophers Slack channel.\n\n## Contributing\n\nFor further developing or contributing to `dst`, check out [these notes](https://github.com/dave/dst/blob/master/contributing.md).\n\n## Special thanks\n\nThanks very much to [hawkinsw](https://github.com/hawkinsw) for taking on the task of adding generics compatibility to `dst`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave%2Fdst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdave%2Fdst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave%2Fdst/lists"}