resolve

package
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

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

func Names(ctx context.Context, paths []string, opts ...Option) (map[string]string, error)

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"
)

func (Error) Error

func (e Error) Error() string

type Option

type Option func(options) options

Option configures Names.

func WithBuildFlags

func WithBuildFlags(flags ...string) Option

WithBuildFlags passes flags to "go list", as in -tags or -mod=mod.

func WithDir

func WithDir(dir string) Option

WithDir loads the packages as if from dir.

"go list" runs there, so dir has to sit in a module requiring the paths being asked about. Without it the current working directory is used, which is right only when the process already runs inside that module.

func WithEnv

func WithEnv(env []string) Option

WithEnv replaces the environment "go list" runs with, in the form os.Environ returns.

Use it to pin GOFLAGS, GOPATH or GOMODCACHE. An empty slice leaves the process environment alone.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL