Documentation
¶
Overview ¶
Package resolve reads the name each imported package declares.
github.com/go-openapi/codegen/formatting.Format never loads a package, so it cannot name one whose package clause does not follow its import path: "github.com/json-iterator/go" declares jsoniter and "github.com/prometheus/client_model/go" declares io_prometheus_client. It keeps such an import rather than delete one the code may be using, and lists it in the report.
Names loads those packages and answers outright. Feed it what the report could not settle, and pass the map back:
report, err := formatting.Format(out, rendered)
if err != nil {
return err
}
if report.HasImportsInDoubt() {
names, err := resolve.Names(ctx, report.PathsInDoubt(), resolve.WithDir(moduleDir))
if err != nil {
return err
}
// format again with formatting.WithResolvedImports(names)
}
Resolve once, not on every run ¶
The answer depends on the dependencies and on nothing else — not on the machine, the module cache or the build list. So run this once, commit the map, and every generator run anywhere agrees. That is the whole reason github.com/go-openapi/codegen/formatting does not resolve imports itself: a generator that searched the build list would produce different files on different machines.
Rerun it when a dependency is added, or when one renames its package. Nothing detects that for you.
What it does not check ¶
Names answers for any path go list can find, an internal package of another module included. Nothing here asks whether the importing file may legally use it: go build rejects such an import and names the file and the line.
What it costs ¶
Names runs "go list" through golang.org/x/tools/go/packages, so it needs the go toolchain and a module that requires the paths being asked about. It is far slower than formatting, which is why it belongs in a separate step rather than inside github.com/go-openapi/codegen/formatting.Format.
Example ¶
Example runs the whole loop: format, resolve what the report could not settle, format again.
One pass over the generated tree produces the map. Commit it, and every later run needs only [formatting.WithResolvedImports], with no toolchain and no module cache.
package main
import (
"context"
"fmt"
"io"
"log"
"os"
"github.com/go-openapi/codegen/formatting"
"github.com/go-openapi/codegen/formatting/resolve"
)
func main() {
const rendered = `package p
import (
"bytes"
"golang.org/x/tools/go/ast/astutil"
)
var _ bytes.Buffer
`
report, err := formatting.Format(io.Discard, []byte(rendered))
if err != nil {
log.Fatal(err)
}
fmt.Println("first pass leaves in doubt:", report.PathsInDoubt())
names, err := resolve.Names(context.Background(), report.PathsInDoubt())
if err != nil {
log.Fatal(err)
}
settled, err := formatting.Format(os.Stdout, []byte(rendered), formatting.WithResolvedImports(names))
if err != nil {
log.Fatal(err)
}
fmt.Println("still in doubt:", settled.HasImportsInDoubt())
}
Output: first pass leaves in doubt: [golang.org/x/tools/go/ast/astutil] package p import ( "bytes" ) var _ bytes.Buffer still in doubt: false
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Names ¶
Names returns the name each import path declares, ready for github.com/go-openapi/codegen/formatting.WithResolvedImports.
It loads the packages, so it needs the go toolchain and a module requiring them: see WithDir. An empty or nil paths leaves it returning an empty map and no error, so a caller may hand it github.com/go-openapi/codegen/formatting.ImportsReport.PathsInDoubt without checking first.
A path that does not resolve is left out of the map, and the error wraps ErrUnresolved and names every one of them with what go list said, as in "no required module provides package X". The map still holds what did resolve, so use it and report the rest:
names, err := resolve.Names(ctx, paths)
if err != nil && !errors.Is(err, resolve.ErrUnresolved) {
return err
}
Duplicate paths are asked once. The map has one entry per distinct path.
Example ¶
ExampleNames reads the name a package declares, which its import path does not give.
package main
import (
"context"
"fmt"
"log"
"github.com/go-openapi/codegen/formatting/resolve"
)
func main() {
names, err := resolve.Names(context.Background(), []string{
"net/http",
"math/rand/v2",
"golang.org/x/tools/go/ast/astutil",
})
if err != nil {
log.Fatal(err)
}
for _, importPath := range []string{"net/http", "math/rand/v2", "golang.org/x/tools/go/ast/astutil"} {
fmt.Printf("%-34s %s\n", importPath, names[importPath])
}
}
Output: net/http http math/rand/v2 rand golang.org/x/tools/go/ast/astutil astutil
Types ¶
type Error ¶
type Error string
Error is a string that implements error, so a sentinel below can be a constant.
const ( // ErrResolve matches every error [Names] returns. ErrResolve Error = "cannot resolve import names" // ErrUnresolved is returned when a path did not come back with a name. The map still holds every // path that did, so a caller may use what resolved and act on the rest. ErrUnresolved Error = "some import paths did not resolve" )
type Option ¶
type Option func(options) options
Option configures Names.
func WithBuildFlags ¶
WithBuildFlags passes flags to "go list", as in -tags or -mod=mod.