erroranalysis

package
v1.0.0-alpha.24 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package erroranalysis infers, from the Go source itself, which domain error constructors a service interface method can return.

The OpenAPI error-response generator used to read a hand-maintained "errors: domain.ErrX, domain.ErrY" line from each interface method's doc comment. That list rots: it is written once and never re-checked against the code. This package derives the same list by following the error value through the call graph, so the spec tracks the implementation.

How it works

For every method on an interface named *Service in the service package, the analyzer finds the concrete implementation and walks its body, tracking which domain error constructors can reach an error-typed return position:

  • a returned domain.ErrX(...) call contributes domain.ErrX;
  • a returned variable contributes whatever was assigned to it, so err := s.foo(); ...; return err pulls in s.foo's error set;
  • a returned call contributes that callee's error set, recursively;
  • errors.AsType[domain.Error](err) propagates err's set to its target, which is how the transaction-unwrap idiom keeps its inner errors, as does errors.As(err, &target) through its pointer argument.

Errors only *inspected* (errors.Is(err, domain.ErrY())) never reach a return position, so they are correctly excluded — that is the whole reason this is a dataflow analysis and not a grep for "domain.Err".

Prerequisites

The analysis type-checks the module, so it needs a tree that compiles: every generated file the analyzed packages import — enumer output, ogen output — must already exist. That makes this a real ordering constraint on code generation, not just on the build.

Dynamic dispatch

Calls through an interface are resolved to every concrete implementation loaded from the module, unioned. That is exact for the storage statements (all dialects raise the same domain errors) but too coarse for a fan-out like UserService.ApplyActions, which invokes Prepare/Apply on an interface-typed variadic parameter: unioned blindly, deleting a user would advertise the errors of creating one.

So call sites bind concrete types to interface-typed parameters, and the callee is analyzed once per binding. ApplyActions analyzed with actions=[*CreateUserAction] resolves action.Prepare to (*CreateUserAction).Prepare and nothing else. Bindings flow through range loops and closures, which is what the transaction callback needs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Analyze

func Analyze(cfg Config) (map[string]Method, error)

Analyze loads the module and infers the error set of every entry-point interface method.

Types

type Config

type Config struct {
	// Dir is the directory to load packages from (the module root).
	Dir string
	// Patterns are the go/packages load patterns. Defaults to ./internal/...
	Patterns []string
	// ModulePrefix limits analysis to packages inside the module; calls into
	// anything else are treated as opaque.
	ModulePrefix string
	// DomainPkgPath is the package holding the ErrXxx constructors.
	DomainPkgPath string
	// InterfaceSuffix selects the entry-point interfaces. Defaults to "Service".
	InterfaceSuffix string
	// EntryPkgPath is the package holding the entry-point interfaces.
	EntryPkgPath string
	// HandlerPkgPath and HandlerTypeName add the API handler's methods as
	// entry points in their own right, keyed "<HandlerTypeName>.<Method>".
	//
	// An operation's error set is not the union of the services its handler
	// calls: the handler raises errors of its own before it reaches them, and
	// the authorization guards are the loudest example — a request for a
	// project the token is not bound to never touches a service, yet answers
	// with that resource's not-found or permission-denied. Analyzing the
	// handler itself picks those up, and reaches the services through the same
	// call graph walk, so the handler set subsumes the service union.
	HandlerPkgPath  string
	HandlerTypeName string
}

Config selects what to load and which packages carry meaning.

type Method

type Method struct {
	Interface string
	Name      string
	// Errors are the domain constructor references ("domain.ErrUserNotFound")
	// the method can return, sorted.
	Errors []string
	// Unimplemented is true when no concrete implementation was found, which
	// means Errors is empty for lack of evidence rather than by analysis.
	Unimplemented bool
}

Method is one analyzed interface method.

func (Method) Key

func (m Method) Key() string

Key is the "Interface.Method" identifier the generator indexes by.

Jump to

Keyboard shortcuts

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