Documentation
¶
Index ¶
- Variables
- func JSONPointer(segments ...string) string
- type EntityDecl
- func (d *EntityDecl) Comments() *ast.CommentGroup
- func (d *EntityDecl) DefKey() string
- func (d *EntityDecl) EnumSourcePkg() (*packages.Package, bool)
- func (d *EntityDecl) File() *ast.File
- func (d *EntityDecl) HasModelAnnotation() bool
- func (d *EntityDecl) HasParameterAnnotation() bool
- func (d *EntityDecl) HasResponseAnnotation() bool
- func (d *EntityDecl) HasSource() bool
- func (d *EntityDecl) Imports() ([]*ast.ImportSpec, bool)
- func (d *EntityDecl) IsAlias() bool
- func (d *EntityDecl) ModelOverrideSuppressed() bool
- func (d *EntityDecl) Name() string
- func (d *EntityDecl) Names() (name, goName string)
- func (d *EntityDecl) Obj() *types.TypeName
- func (d *EntityDecl) ObjType() types.Type
- func (d *EntityDecl) PkgImport(path string) (*packages.Package, bool)
- func (d *EntityDecl) PkgPath() string
- func (d *EntityDecl) Pos() token.Pos
- func (d *EntityDecl) SuppressModelOverride()
- func (d *EntityDecl) TypeExpr() (ast.Expr, bool)
- func (d *EntityDecl) WrittenRHS() (types.Type, bool)
- type Options
- type ParameterRef
- type Provenance
- type ScanCtx
- func (s *ScanCtx) AddDiscoveredModel(decl *EntityDecl)
- func (s *ScanCtx) BeginDefOrigins(defKey string)
- func (s *ScanCtx) BeginDeferredOrigins(key string)
- func (s *ScanCtx) CleanGoDoc() bool
- func (s *ScanCtx) DeclForType(t types.Type) (*EntityDecl, bool)
- func (s *ScanCtx) DefaultAllOfForEmbeds() bool
- func (s *ScanCtx) DescWithRef() bool
- func (s *ScanCtx) DropDefOrigins(defKey string)
- func (s *ScanCtx) DropDeferredOrigins(key string)
- func (s *ScanCtx) EmitDiagnostic(d grammar.Diagnostic)
- func (s *ScanCtx) EmitHierarchicalNames() bool
- func (s *ScanCtx) EmitRefSiblings() bool
- func (s *ScanCtx) EmitXGoType() bool
- func (s *ScanCtx) EndDefOrigins()
- func (s *ScanCtx) EndDeferredOrigins()
- func (s *ScanCtx) ExtraModels() iter.Seq2[*ast.Ident, *EntityDecl]
- func (s *ScanCtx) FileForPos(pkgPath string, pos token.Pos) (*ast.File, bool)
- func (s *ScanCtx) FileSet() *token.FileSet
- func (s *ScanCtx) FindComments(pkg *packages.Package, name string) (*ast.CommentGroup, bool)
- func (s *ScanCtx) FindDecl(pkgPath, name string) (*EntityDecl, bool)
- func (s *ScanCtx) FindEnumValues(pkg *packages.Package, enumName string) (list []any, descList []string, posList []token.Pos, _ bool)
- func (s *ScanCtx) FindModel(pkgPath, name string) (*EntityDecl, bool)deprecated
- func (s *ScanCtx) FindModelsByLeaf(name string) []*EntityDecl
- func (s *ScanCtx) FlushDefOrigins(finalName func(defKey string) string)
- func (s *ScanCtx) FlushDeferredOrigins()
- func (s *ScanCtx) GetModel(pkgPath, name string) (*EntityDecl, bool)
- func (s *ScanCtx) Mangler() *mangling.NameMangler
- func (s *ScanCtx) Meta() iter.Seq[*ast.CommentGroup]
- func (s *ScanCtx) Models() iter.Seq2[*ast.Ident, *EntityDecl]
- func (s *ScanCtx) MoveExtraToModel(k *ast.Ident)
- func (s *ScanCtx) NameConcatBudget() float64
- func (s *ScanCtx) NameFromTags() []string
- func (s *ScanCtx) NumExtraModels() int
- func (s *ScanCtx) OnDiagnostic() func(grammar.Diagnostic)
- func (s *ScanCtx) Operations() iter.Seq[parsers.ParsedPathContent]
- func (s *ScanCtx) OriginEnabled() bool
- func (s *ScanCtx) ParamOrigin(opID, name string) (token.Position, bool)
- func (s *ScanCtx) ParameterRefs() iter.Seq[*ParameterRef]
- func (s *ScanCtx) Parameters() iter.Seq[*EntityDecl]
- func (s *ScanCtx) PkgForType(t types.Type) (*packages.Package, bool)
- func (s *ScanCtx) PosOf(p token.Pos) token.Position
- func (s *ScanCtx) PruneUnusedModels() bool
- func (s *ScanCtx) RecordOrigin(pointer string, pos token.Position)
- func (s *ScanCtx) RecordParamOrigin(opID, name string, pos token.Position)
- func (s *ScanCtx) RefAliases() bool
- func (s *ScanCtx) Responses() iter.Seq[*EntityDecl]
- func (s *ScanCtx) Routes() iter.Seq[parsers.ParsedPathContent]
- func (s *ScanCtx) SetXNullableForPointers() bool
- func (s *ScanCtx) SingleLineCommentAsDescription() bool
- func (s *ScanCtx) SkipAllOfCompounding() bool
- func (s *ScanCtx) SkipEnumDescriptions() bool
- func (s *ScanCtx) SkipExtensions() bool
- func (s *ScanCtx) SkipJSONifyInterfaceMethods() bool
- func (s *ScanCtx) SourcelessPackage(pkgPath string) (reason string, sourceless bool)
- func (s *ScanCtx) TransparentAliases() bool
- type TypeIndex
- type TypeIndexOption
- func WithAfterDeclComments(enabled bool) TypeIndexOption
- func WithExcludeDeps(excluded bool) TypeIndexOption
- func WithExcludePkgs(excluded []string) TypeIndexOption
- func WithExcludeTags(excluded map[string]bool) TypeIndexOption
- func WithIncludePkgs(included []string) TypeIndexOption
- func WithIncludeTags(included map[string]bool) TypeIndexOption
- func WithOnDiagnostic(cb func(grammar.Diagnostic)) TypeIndexOption
- func WithRefAliases(enabled bool) TypeIndexOption
- func WithTransparentAliases(enabled bool) TypeIndexOption
- func WithXNullableForPointers(enabled bool) TypeIndexOption
Constants ¶
This section is empty.
Variables ¶
var ErrDegradedLoad = errors.New("degraded package load")
ErrDegradedLoad is the base error for a degraded package load detected by detectDegradedLoad (no packages matched, or a scanned package failed to load / type-check).
It is wrapped with the per-package detail and, at the public API boundary, with ErrCodeScan.
var ErrScanner = errors.New("codescan:scanner")
ErrScanner is the sentinel error for all errors originating from the scanner package.
Functions ¶
func JSONPointer ¶ added in v0.35.0
JSONPointer builds an RFC 6901 pointer from raw (unescaped) segments, escaping each per the spec (~ → ~0, / → ~1).
The output matches what the spec-side index derives via jsontext, so source- and spec-side pointers for the same node are byte-identical and join cleanly.
Types ¶
type EntityDecl ¶
type EntityDecl struct {
Type *types.Named
Alias *types.Alias // added to supplement Named, after go1.22
// contains filtered or unexported fields
}
EntityDecl is a type declaration the scanner classified, in two halves.
The TYPE half — Type / Alias, and the Obj, ObjType, Name, Pos, PkgPath accessors built on them — is always available: it comes from the type-checker, and a package served from compiled export data carries it in full (positions included: time.Duration reports $GOROOT/src/time/time.go).
The SYNTAX half — the comment group, the declaring identifier, the type spec, the enclosing file and the loaded package — comes from parsed source, which a package need not have. It is unexported, and reachable only through accessors that make its absence expressible: HasSource answers whether there is any, Comments and File answer nil when there is none, and TypeExpr / Imports / PkgImport / EnumSourcePkg return a second result the caller has to handle.
Reach for it only for what genuinely needs source; a name, a position or a package path must come from the type half, or the declaration stops working the moment its source is not read. See [§declaration](./README.md#declaration).
func (*EntityDecl) Comments ¶
func (d *EntityDecl) Comments() *ast.CommentGroup
Comments returns the declaration's swagger annotations and godoc, or nil when it carries none.
Nil is the ordinary answer for a declaration with no doc comment, so it is also the honest answer for one with no source: every consumer already reads nil as "no annotations here".
func (*EntityDecl) DefKey ¶ added in v0.35.0
func (d *EntityDecl) DefKey() string
DefKey returns the fully-qualified, compiler-unique definition key for this declaration: "<pkgpath>/<name>", where <name> is the swagger:model override when present, else the Go type name (the first return of Names).
This is the build-time key for the definitions map and for every "#/definitions/" $ref target, so two distinct Go types that share a short name can never collide before the spec.Builder's reduce stage shortens names back.
§12.1).
Universe / package-less types (no enclosing package) fall back to the bare name; in practice those are intercepted as stdlib specials before they ever reach a definition key.
func (*EntityDecl) EnumSourcePkg ¶ added in v0.36.4
func (d *EntityDecl) EnumSourcePkg() (*packages.Package, bool)
EnumSourcePkg returns the loaded package this declaration's source was read from, for the one consumer that needs the package rather than the declaration: collecting a swagger:enum's const values.
Reports false when there is no source, and the enum then has no members — ScanCtx.FindEnumValues reads the const block from the package's own syntax, which is precisely what is missing.
func (*EntityDecl) File ¶
func (d *EntityDecl) File() *ast.File
File returns the source file the declaration was read from, or nil when it was not read from one.
Nil is a legitimate answer — see [resolvers.FindASTField], the only consumer, which yields no field for it.
func (*EntityDecl) HasModelAnnotation ¶
func (d *EntityDecl) HasModelAnnotation() bool
func (*EntityDecl) HasParameterAnnotation ¶
func (d *EntityDecl) HasParameterAnnotation() bool
func (*EntityDecl) HasResponseAnnotation ¶
func (d *EntityDecl) HasResponseAnnotation() bool
func (*EntityDecl) HasSource ¶ added in v0.36.4
func (d *EntityDecl) HasSource() bool
HasSource reports whether this declaration's source was parsed.
False means the type half is all there is: the declaration comes from a package whose types were read from compiled export data with no syntax attached. Every syntax accessor then answers nothing, and a caller that cannot proceed without source must say so rather than guess from the type half — Underlying is not the written right-hand side, and a missing comment is not an absent annotation.
func (*EntityDecl) Imports ¶ added in v0.36.4
func (d *EntityDecl) Imports() ([]*ast.ImportSpec, bool)
Imports returns the import declarations of the file the type was declared in.
Reports false when there is no source. Imports are how a `pkg.Type` doc-link resolves its qualifier to a package path, and only the file records the spelling: an import alias exists nowhere else.
func (*EntityDecl) IsAlias ¶ added in v0.36.4
func (d *EntityDecl) IsAlias() bool
IsAlias reports whether the declaration was written with alias syntax (`type X = Y`).
The type-checker's answer to what the source spells `Spec.Assign.IsValid()`: since go1.22 an alias declaration defines a *types.Alias, so the shape is readable without the source.
func (*EntityDecl) ModelOverrideSuppressed ¶ added in v0.35.0
func (d *EntityDecl) ModelOverrideSuppressed() bool
ModelOverrideSuppressed reports whether SuppressModelOverride was set.
func (*EntityDecl) Name ¶ added in v0.36.4
func (d *EntityDecl) Name() string
Name returns the Go name of the declared type.
It reads the type-checker's object rather than the declaring identifier, so it answers for a declaration whose source was never parsed.
func (*EntityDecl) Names ¶
func (d *EntityDecl) Names() (name, goName string)
func (*EntityDecl) Obj ¶
func (d *EntityDecl) Obj() *types.TypeName
Obj returns the type name for the declaration defining the named type or alias t.
func (*EntityDecl) ObjType ¶
func (d *EntityDecl) ObjType() types.Type
func (*EntityDecl) PkgImport ¶ added in v0.36.4
func (d *EntityDecl) PkgImport(path string) (*packages.Package, bool)
PkgImport returns the loaded package the declaring package imports under path.
Reports false when there is no source, and when nothing under that path was loaded. It is the other half of Imports: the file supplies the path, this supplies the package's own name — which need not be the path's last segment, so an unaliased import cannot be spelled without it.
func (*EntityDecl) PkgPath ¶ added in v0.36.4
func (d *EntityDecl) PkgPath() string
PkgPath returns the import path of the package declaring the type, or "" for a package-less (universe) type.
func (*EntityDecl) Pos ¶ added in v0.36.4
func (d *EntityDecl) Pos() token.Pos
Pos returns the position of the declared type's name.
Obj().Pos() is the position the type-checker recorded, which compiled export data carries too — so this is the position accessor to reach for, never Ident.Pos() / Spec.Pos(). For a package loaded from source the three are the same token: ast.TypeSpec.Pos() is its Name.Pos(), and that identifier is the key Defs maps to the object.
func (*EntityDecl) SuppressModelOverride ¶ added in v0.35.0
func (d *EntityDecl) SuppressModelOverride()
SuppressModelOverride drops this declaration's `swagger:model <name>` override so that Names / DefKey fall back to the Go type name.
Used to resolve a same-package duplicate, where two distinct types in one package claim the same override name (a user error): the first keeps the name, later ones revert to their Go name.
func (*EntityDecl) TypeExpr ¶ added in v0.36.4
func (d *EntityDecl) TypeExpr() (ast.Expr, bool)
TypeExpr returns the right-hand side of the declaration AS WRITTEN — the `time.Time` in `type Stamp time.Time`, the struct or interface literal in a struct or interface declaration.
Reports false when there is no source. go/types keeps no record of the written form on a defined type, so there is nothing to fall back on: Underlying peels exactly the named layer the stdlib recognizers key on. A caller that only needs a plausible shape may fall back to it deliberately; one that needs the written form has to give up.
func (*EntityDecl) WrittenRHS ¶ added in v0.36.4
func (d *EntityDecl) WrittenRHS() (types.Type, bool)
WrittenRHS returns the type this declaration was WRITTEN over — `Stamp` in `type StampResp Stamp` — as opposed to the fully peeled underlying that types.Named.Underlying yields.
The distinction matters wherever a named layer carries meaning: a stdlib recognizer keys on `time.Time`, which peeling discards, and a `swagger:strfmt` may sit one declaration to the right of the one being built.
go/types keeps no record of it on a defined type, so the answer comes from the right-hand side expression. It is resolved against the type-checker's own scopes rather than through types.Info.Types: a package scope is complete whether the package was checked from source or read from compiled export data, while the expression records exist only for a source type-check and cannot be reconstructed outside go/types.
Returns (nil, false) when the declaration has no syntax, or when the right-hand side is a shape this resolution declines to guess at (a generic instantiation, a dot-imported name). A caller that only needs a plausible shape should fall back to Underlying.
type Options ¶
type Options struct {
Packages []string
InputSpec *spec.Swagger
ScanModels bool
WorkDir string
BuildTags string
// GOOS and GOARCH select the platform the scanned code is built for.
//
// They decide which files each package is made of — //go:build lines and _linux.go / _amd64.go
// style filename suffixes resolve against them — so they change the emitted spec, in the same way
// BuildTags does.
//
// Empty (the default) means the platform codescan itself is running on, which is what the go
// command would assume. Set them to scan code for another platform, or wherever codescan's own
// platform is an accident of deployment rather than a statement about the code under scan.
GOOS string
GOARCH string
// GOFLAGS, GOWORK and GOEXPERIMENT complete the picture GOOS/GOARCH starts: the go environment
// that decides WHAT is built, rather than where the output goes.
//
// They are options rather than inherited state for the same reason GOOS is. A scan that silently
// picks them up from whatever shell it started in is not reproducible, and an inherited value is
// easy to apply on one code path and forget on another.
//
// Empty means "whatever the process environment says", which is what the go command would do.
//
// - GOFLAGS supplies default command-line flags ("-tags=integration"); flags given through
// BuildTags win, as they do for the go command.
// - GOWORK selects the workspace: "off" disables it, a path names a go.work, empty searches
// upwards. Inside a workspace a sibling module resolves to the copy being worked on rather
// than to the module cache — miss that and its types are read stale, or synthesized empty.
// - GOEXPERIMENT enables toolchain experiments ("jsonv2"), each contributing a
// goexperiment.<name> build tag.
GOFLAGS string
GOWORK string
GOEXPERIMENT string
// ToolchainFreeLoader runs the scan through codescan's own package loader (internal/packages)
// instead of golang.org/x/tools/go/packages.
//
// The two do the same job and, across codescan's fixture corpus, produce identical specs. They
// differ in what they need to run: go/packages resolves the package graph by executing `go list`,
// so it requires an installed toolchain and the ability to start a process; this one is pure Go and
// requires neither.
//
// False (the default) keeps the historic go/packages behaviour. Setting FS implies this regardless,
// since `go list` can only ever read the real filesystem.
//
// Experimental: the toolchain-free loader is younger than the go/packages path it stands in for,
// and its shape may change. Leaving it false is unaffected.
ToolchainFreeLoader bool
// FS makes the scan read its source through a virtual filesystem instead of the real one.
//
// This is what lets codescan scan a tree that was never written to disk: an in-memory tree in a
// WASI guest, an uploaded archive, a testing/fstest.MapFS.
//
// # FS is the whole world, not just the tree being scanned
//
// Dependencies and the standard library are read through it too. A filesystem holding only the
// module under scan resolves neither, since neither GOROOT nor the module cache lives inside a
// module — every import outside it is then synthesized from the names selected through it, and the
// spec comes out valid and quietly thinner (a lost format, a lost byte-array rendering). That is
// announced rather than fatal: one scan.synthesized-import per unresolved import, plus
// scan.degraded-load. Seeing those against a tree you expected to be complete means FS is missing
// something, not that the source is wrong.
//
// # Paths
//
// Packages, WorkDir and every path the scan derives are interpreted against the root of FS,
// following io/fs conventions: slash-separated and unrooted. An absolute path is mapped onto that
// convention by dropping its leading separator, which is what lets an unrooted tree be used at all.
// The corollary is that a tree meaning to serve GOROOT or the module cache must mirror their
// absolute layout beneath its own root — /usr/lib/go/src/... is looked up as usr/lib/go/src/... —
// and that such a tree is therefore tied to the host it was recorded from.
//
// # Supplying the half that is not the module under scan
//
// Three ways, in descending fidelity: mirror it in the tree, as above; ExportData, which carries
// the compiler's own types and costs no fidelity but is valid only for the toolchain that produced
// it; or StubStdlib, which trades fidelity for reach and needs nothing mounted. See each.
//
// For the case FS was built for — an embed.FS — what can be embedded decides the recipe. A module's
// own source and its vendor directory can, since both are inside the module; GOROOT cannot. So:
//
// go mod vendor, then embed the module source + non-stdlib dependencies, read as usual
// ExportData alongside it the standard library
//
// ExportData is itself an fs.FS, so it embeds too, and the two halves ship as one binary. Vendoring
// preserves a dependency's own annotations — a vendored go-openapi/strfmt is read from inside
// the tree, marks and all. StubStdlib substitutes for the second line where no blob can be
// produced, at the fidelity cost documented there.
//
// Setting FS implies ToolchainFreeLoader: `go list` reaches the filesystem by running a process
// against the real one, so it could not honour FS even if asked.
//
// Experimental: see ToolchainFreeLoader.
FS fs.FS
// StubStdlib keeps the standard library out of the package graph, synthesizing its types from the
// names the scanned code selects through them rather than reading GOROOT.
//
// It applies only to the toolchain-free loader; the go/packages path ignores it.
//
// The trade is fidelity for reach. Recognition by type identity is unaffected — time.Time,
// json.RawMessage and the rest are matched on (package, name). Anything structural is lost: a
// synthesized type has no fields and no method set, so json.RawMessage no longer renders as a byte
// array, time.Duration no longer as an integer, and a type is no longer seen to implement
// encoding.TextMarshaler.
//
// It removes the need for GOROOT entirely, and shrinks the graph, which makes a scan viable in a
// WASI guest or a browser, where the standard library source would otherwise have to be shipped or
// mounted.
//
// It is not failsafe, and the failure mode is quiet: a spec comes out subtly thinner rather than
// erroring. Across codescan's own fixture corpus 133 of 138 scans are byte-identical; the rest lose
// a byte-array rendering, an integer format, or a TextMarshaler-derived string, and stdlib
// interfaces such as io.Reader have no identity recognizer to fall back on at all. Prefer a full
// graph wherever GOROOT is available.
//
// Experimental: see ToolchainFreeLoader.
StubStdlib bool
// CompiledDependencies takes dependency types from the compiler's export data, instead of reading
// every dependency from source.
//
// Unset, a scan parses and type-checks the whole dependency graph, which is most of what a load
// does. Set, that work is skipped for anything outside the scanned module: the compiler already did
// it, and `go list -export` hands the result over.
//
// Setting it costs no meaning. Export data carries the full exported type surface — fields,
// method sets, interface identity — but no syntax and no comments, and a scan wants two different
// things out of a dependency's source. Scanning its files for the annotation marker after the load
// recovers what a dependency says about its own types, so go-openapi's own strfmt marks keep giving
// a strfmt.DateTime field its date-time format. What a dependency DECLARES
// cannot be anticipated that way, since any package may declare a type the scanned code names as a
// model, so its declaration is fetched at the lookup that wants it. A dependency nothing reaches
// into is never read at all, and the document is the one the ordinary loader produces —
// pinned over the whole fixture corpus by internal/integration/loader_agreement_test.go.
//
// # When to set it
//
// Cost, and only cost — but the cost swings both ways, which is why this is a choice and not a
// default. On a warm build cache it is roughly 2.3x faster and holds a third of the memory. On a
// cold one it is an order of magnitude slower, since export data has to be compiled before it
// exists, and it writes around 229 MB of build cache on a large tree.
//
// So it pays where the cache is warm by construction: a developer's own machine, a watch loop, a
// pipeline that restores its cache. It loses badly on a clean checkout, which is what a CI runner
// usually is — and that is the case the default protects. Under a memory bound rather than a time
// one, ToolchainFreeLoader is the better answer than either: leaner than a source load and, unlike
// this, indifferent to the state of the cache.
//
// A closure that does not compile is NOT a reason to avoid it: the load is retried from source and
// the spec comes out the same.
//
// The option applies to the go/packages loader alone. The toolchain-free loader resolves imports
// itself and already decides per dependency whether to read its source, so it neither needs this
// nor honours it; ExportData below is the same idea supplied by hand for that loader.
//
// So there is nothing here to ask for wherever go/packages cannot run. A WebAssembly build has
// no process model and therefore no `go list`, and setting FS forces the same loader for the same
// reason — in both, dependency types come from source or from ExportData regardless of this field.
CompiledDependencies bool
// ExportData serves DEPENDENCIES from pre-computed export data instead of reading their source,
// under the toolchain-free loader.
//
// It holds one file per package, named by import path with a ".export" suffix. Unlike StubStdlib
// this costs no fidelity — the types are the ones the compiler computed, so fields, method sets
// and interface identity are all real — while avoiding the parsing and type-checking that
// dominate a full scan.
//
// The module under scan is never read this way: its comments are the annotations, and export data
// carries none. Neither is a dependency that has something to say — one whose source carries
// swagger annotations is read from source in the ordinary way, so a swagger:strfmt written in a
// library still counts. Export data serves everything else, which is where the time goes anyway.
//
// Only where a dependency's source cannot be found at all are its annotations lost, and that raises
// a scan.compiled-dependencies Hint naming the package.
//
// Prepare a tree with `go run ./hack/genexportdata`. See internal/scanner/README.md#export-data.
// The data is valid only for the toolchain that produced it, and a package it does not cover falls
// back to source, and then to synthesis.
//
// Experimental: see ToolchainFreeLoader.
ExportData fs.FS
ExcludeDeps bool
Include []string
Exclude []string
IncludeTags []string
ExcludeTags []string
SetXNullableForPointers bool
RefAliases bool // aliases result in $ref, otherwise aliases are expanded
TransparentAliases bool // aliases are completely transparent, never creating definitions
// DescWithRef controls description preservation on $ref'd fields in the
// description-only-decoration case: when a struct field's Go type resolves to a named type ($ref)
// and its only field-level decoration is a description (no validations, no user-authored
// extensions).
//
// - false (default): the description is dropped and the field
// emits as a bare `{$ref: ...}`.
// - true: the description is preserved by wrapping the $ref in
// a single-arm `allOf` compound — `{description: "...",
// allOf: [{$ref}]}` — the JSON-Schema-draft-4 correct shape
// for sibling description.
//
// When the field also carries validation overrides (pattern, enum, example, etc.) or user-authored
// vendor extensions, the allOf compound is mandatory regardless of this flag — the override
// would be lost otherwise.
//
// Deprecated: prefer EmitRefSiblings, which preserves description AND extensions as direct $ref
// siblings (the modern, lenient shape).
// DescWithRef is retained with its original semantics (the strict draft-4 single-arm allOf wrap
// for the description-only case) and remains a no-op when EmitRefSiblings is set.
//
// See [§ref-override](../builders/schema/README.md#ref-override).
DescWithRef bool
// EmitRefSiblings emits a $ref'd field's description and vendor extensions as DIRECT siblings of
// the `$ref` (`{$ref, description, x-*}`) instead of wrapping them in an allOf compound.
//
// Strict JSON-Schema-draft-4 ignores siblings of `$ref` (hence the default allOf wrap), but
// OpenAPI 3.1 / JSON Schema 2020-12 and most modern Swagger-UI renderers honour them.
//
// - false (default): description / extensions follow the legacy
// wrap behaviour (extensions lift onto a single-arm allOf;
// description-only is governed by DescWithRef).
// - true: description and extensions ride directly alongside the
// `$ref`, no allOf.
//
// Validations and externalDocs are NOT siblings-eligible: when present they still force an allOf
// compound (validations on the override arm), and description / extensions then ride the outer
// compound.
// This flag changes only the no-forced-compound cases.
//
// See [§ref-override](../builders/schema/README.md#ref-override).
EmitRefSiblings bool
// SkipAllOfCompounding disables the allOf-compound rewrite for $ref'd struct fields entirely: no
// allOf compound is ever emitted.
//
// - false (default): siblings are preserved via the allOf compound
// (or, under EmitRefSiblings, as direct $ref siblings).
// - true: no compound is produced. Validations and externalDocs —
// which can only ride a compound — are DROPPED. Description and
// extensions are likewise dropped UNLESS EmitRefSiblings is also
// set, in which case they survive as direct `$ref` siblings.
// Every drop raises one diagnostic through OnDiagnostic — the
// loss is never silent.
//
// `required:` is a parent-side concern (it lands on the enclosing object's `required` list, not as
// a $ref sibling) and is preserved regardless of this flag.
//
// Intended for downstream consumers (e.g. go-swagger codegen) that expect a bare `$ref` for a
// field pointing at a model and do not handle the allOf-compounded shape.
// See [§ref-override].
SkipAllOfCompounding bool
// DefaultAllOfForEmbeds changes how a plain (non-`swagger:allOf`-tagged) struct embed renders:
// into allOf composition instead of inlined properties.
//
// By default codescan inlines an embedded struct's properties into the embedding schema (mirroring
// Go field promotion), so the "this composes Y" relationship is lost — every embedding struct
// emits a flat copy of the embedded fields.
//
// Downstream client generators that want a reusable base type per embed prefer the composition
// shape instead.
//
// - false (default): plain embeds inline their properties (existing
// behaviour).
// - true: a plain embed is treated as if it carried `swagger:allOf` —
// it becomes an allOf member ($ref to the embedded type's definition
// when that type is a model, otherwise an inline member), and the
// embedding struct's own fields move into a sibling allOf member.
//
// Scope and precedence:
// - Only STRUCT embeds are affected. Interface embeds already compose via
// allOf and are unchanged.
// - An explicit `swagger:allOf` annotation already produces this shape;
// the flag only makes it the default for untagged embeds.
// - An embed carrying an explicit json tag name (or `swagger:name`) is a
// single named property, not a promotion, so it is left as a nested
// property regardless of this flag (go-swagger#2038).
// - Pointer embeds are peeled; aliased embeds resolve to their unaliased
// type; stdlib specials (`error`, `time.Time`) keep their canonical
// recognizer shape — all via the existing allOf path.
//
// See [§allof](../builders/schema/README.md#allof).
DefaultAllOfForEmbeds bool
SkipExtensions bool // skip generating x-go-* vendor extensions in the spec
// NameFromTags is the ordered list of struct-tag types consulted to derive the emitted name of a
// schema property, parameter, or response header from a Go struct field.
//
// The first listed tag type that supplies a usable name wins; a tag type that is absent or carries
// only options (e.g. `,omitempty`) is skipped and the next is tried.
// When no listed tag names the field, the Go field name is used.
//
// - nil / unset (default): ["json"] — the historic behaviour.
// - explicit empty slice: no struct tag is consulted; the name derives
// from the Go field name.
// - e.g. ["form","json"]: prefer the `form:` name (used by gin), falling
// back to `json:` (go-swagger#2912, go-swagger#1391).
//
// Only the NAME is sourced this way.
// The encoding/json directives `-` (exclude), `,omitempty` (→ not required) and `,string` are
// always read from the `json` tag regardless of this setting.
//
// Targeted renames — the `name:` keyword (parameters / response headers) and `swagger:name` /
// `swagger:model {name}` (schema) — still take precedence over any tag-derived name.
NameFromTags []string
// SkipJSONifyInterfaceMethods opts out of the auto-jsonify mangler applied to interface-method
// property names.
//
// An interface method has no "natural" JSON serialization (Go's encoding/json cannot marshal
// embedded interface methods without a custom marshaler), so codescan invents a default property
// name by running the swag/mangling ToJSONName transform on the Go method name (`CreatedAt` →
// `createdAt`, `ID` → `id`).
//
// This convention will not always match the author's intent — e.g. an interface already named
// for its JSON shape, or a codebase with its own canonical-name discipline.
//
// - false (default): interface-method names auto-jsonify (existing
// behaviour).
// - true: the Go method name is emitted verbatim; the mangler is skipped.
//
// A `swagger:name X` override is taken verbatim regardless of this flag — it already bypasses
// the mangler.
// This flag only changes the fallback used when no override is present.
// It does not affect struct-field naming, which mirrors what encoding/json actually produces.
//
// See [§interface-naming](../builders/schema/README.md#interface-naming).
SkipJSONifyInterfaceMethods bool
// SkipEnumDescriptions controls whether the per-enum-value const-name mapping built from
// `swagger:enum` (e.g. "FIRST TestEnumFirst") is folded into the property / parameter / header
// `description`.
//
// - false (default): the mapping is appended to the authored
// description AND exposed via the `x-go-enum-desc` vendor extension
// (backward-compatible behaviour).
// - true: the description is left as the authored prose; the mapping
// rides `x-go-enum-desc` only.
//
// Independent of SkipExtensions: with SkipExtensions also set, the mapping is suppressed
// everywhere.
// See go-swagger/go-swagger#2922.
SkipEnumDescriptions bool
// NameConcatBudget tunes the readability cutoff used when the name-identity reduce stage
// deconflicts colliding definition names by concatenating package segments (b.Test / c.Test ->
// BTest / CTest).
//
// Each candidate concat is scored in [0,1] — lower is more readable (shorter overall, fewer
// parts, no over-long segment).
// A collision group whose best concat scores ABOVE the budget is a candidate for the hierarchical
// fallback (name-identity Stage 3 / K3).
//
// The zero value selects the built-in default (0.65).
// Raise it toward 1.0 to accept longer concats; lower it to fall back sooner.
NameConcatBudget float64
// EmitHierarchicalNames enables the hierarchical fail-safe for the rare collision groups whose
// best flat concat exceeds NameConcatBudget.
//
// When set, such a group is emitted as nested container definitions (`#/definitions/<pkg>/<Name>`,
// with `additionalProperties:true` + `x-go-package` on each container) instead of a long flat
// concat, and an explanatory diagnostic is raised.
//
// Default false — and deliberately so: a nested definition is a deep JSON pointer that only
// `ExpandSpec` resolves, and a definitions- enumerating consumer (e.g. go-swagger codegen, one
// model per entry) sees the container nodes rather than the models.
//
// The always-correct flat concat stays the default; enable this only when you prefer the nested
// shape for the over-budget tail.
EmitHierarchicalNames bool
// EmitXGoType stamps an `x-go-type` vendor extension on every emitted definition, recording the
// fully-qualified originating Go type (`<package path>.<type name>`) alongside the existing
// `x-go-name` / `x-go-package` traceability extensions.
//
// - false (default): no `x-go-type` is emitted for ordinary types
// (the extension still appears on the narrow special-type cases
// that have always carried it — `error`, the unmodellable
// generic-type fallback).
// - true: each definition carries `x-go-type`, useful for
// round-tripping a generated spec back to its source Go types.
//
// Under the SkipExtensions umbrella: with SkipExtensions also set, no vendor extension is emitted
// regardless.
// See go-swagger/go-swagger#2924.
EmitXGoType bool
// SingleLineCommentAsDescription routes a single-line doc comment to the object's `description`
// regardless of trailing punctuation, never to `title` / `summary`.
//
// - false (default): the first-sentence convention applies — a
// single-line comment ending in punctuation (`.`, `!`, `?`)
// becomes the `title` (model / info) or `summary` (operation);
// without trailing punctuation it is a `description`.
// - true: a single-line comment is always a `description`. Multi-
// line comments keep the existing title/description split (the
// first line, or the paragraph before the first blank line, is
// still the title).
//
// See go-swagger/go-swagger#2626.
SingleLineCommentAsDescription bool
// AfterDeclComments, when set, lets swagger annotations live INSIDE a declaration (the leading
// comment of a struct body) or INLINED as a trailing comment, in addition to the doc comment above
// the declaration.
//
// The godoc above the declaration then stays clean and human-facing while the swagger machinery
// lives out of the published documentation.
// The scanner folds the located comments into the comment source the builders already consume —
// same annotation grammar, no new syntax.
//
// Default false.
//
// v0.36 scope: type declarations (swagger:model / swagger:parameters / swagger:response) —
// struct inside-body leading comments and the trailing comment of an alias / non-struct type.
// Routes / operations are already position-agnostic.
// Struct fields and const enums are follow-ups.
AfterDeclComments bool
// CleanGoDoc rewrites godoc-specific syntax that reads as noise when a title / description is
// carried from a Go doc comment into the spec.
//
// It applies ONLY to godoc-derived prose — author-written swagger:title / swagger:description
// overrides are never touched.
//
// - false (default): godoc prose is emitted verbatim (existing
// behaviour; output is byte-identical).
// - true: godoc doc-link brackets are removed and the identifier is
// humanized (`[CustName]` → "cust name"); reference-style link
// definition lines (`[text]: url`) are dropped; and when a doc-link
// resolves to an emitted schema, it is recomposed to the name that
// schema is actually exposed under (so the prose stays true to the
// generated definitions). The first identifier of a title /
// description is restored to sentence case.
//
CleanGoDoc bool
// PruneUnusedModels, when set together with ScanModels, drops every discovered definition that is
// not transitively referenced from a path, a shared response, a shared parameter, or a definition
// supplied via InputSpec.
//
// It is the middle ground between the two default modes:
//
// - without ScanModels: only route-reachable models are emitted;
// - with ScanModels (`-m`): every swagger:model type is emitted, reachable
// or not;
// - with ScanModels + PruneUnusedModels: swagger:model discovery runs, then
// the unreachable definitions are pruned again — useful when scanning a
// large shared library where only the $ref'd subset is wanted.
//
// Pruning runs BEFORE definition-name reduction, so an unused model can no longer force a spurious
// cross-package name collision on a model that IS used (the survivor keeps its clean short name).
// Definitions supplied via InputSpec are pinned: they are never pruned and seed the reachability
// roots.
//
// Each pruned definition raises a scan.pruned-unused Hint through OnDiagnostic — the loss is
// never silent.
//
// Without ScanModels this flag is a no-op (the emitted set is already reachable-only); setting it
// alone raises one Hint.
// Default false.
//
// Note: a discriminator base references its subtypes by mapping string, not by $ref, so a subtype
// reachable only through a discriminator could be pruned. codescan does not auto-wire
// discriminator subtypes today; revisit if it ever does.
// See go-swagger/go-swagger#2639.
PruneUnusedModels bool
// Debug is deprecated and has no effect.
//
// It formerly enabled verbose debug logging to stderr during scanning.
// That logger was retired: scan-time observations now flow exclusively through OnDiagnostic (which
// the caller routes to a logger of their choice), and codescan no longer writes to stdout/stderr
// — keeping it usable from a TUI or a WASI/WASM host.
//
// Deprecated: wire OnDiagnostic instead.
// This field is retained for API compatibility and is ignored.
Debug bool
// OnDiagnostic, when non-nil, is invoked for every diagnostic the builder layer records
// (lexer/parser warnings, semantic-validation failures from the validations package, etc.).
//
// The callback fires once per diagnostic in source order; diagnostics never block the build —
// invalid constructs are silently dropped from the output spec while their explanation flows
// through this channel.
//
// Experimental: the public API surface for diagnostics is subject to change while LSP integration
// matures.
// See [§diagnostics](./README.md#diagnostics).
OnDiagnostic func(grammar.Diagnostic)
// OnProvenance, when non-nil, is invoked once per anchor node in the produced spec, carrying its
// JSON pointer and the source position of the Go construct that produced it (see [Provenance]).
//
// Anchors are code-detail nodes (type decls, fields, values, route/meta blocks); finer nodes
// resolve to their nearest anchored ancestor at the consumer.
// The callback never blocks the build.
//
// Experimental: the cross-ref surface may change while LSP / TUI integration matures.
OnProvenance func(Provenance)
}
Options configures a scan.
The zero value is a valid configuration: every flag defaults to false and every slice/map defaults to nil.
Details ¶
See [§options](./README.md#options) for the field overview, and [§descwithref](./README.md#descwithref) and [§diagnostics](./README.md#diagnostics) for the two fields with non-trivial semantics (DescWithRef and OnDiagnostic).
type ParameterRef ¶ added in v0.35.1
ParameterRef is a standalone `swagger:parameters` marker hosted by a func (or other non-struct declaration) rather than a struct definition.
Per the disambiguation rule, such a marker is a *reference*: it wires existing shared parameters into an operation or path-item as `$ref`s — its first argument token is the target (an operation id or a `/path`) and the remaining tokens are shared-parameter names.
The scanner only discovers and locates the marker; its target and names are parsed from Comments by the grammar (grammar.ParametersBlock) when the shared-parameters builder consumes it. §1b.
type Provenance ¶ added in v0.35.0
type Provenance struct {
// Pointer is the RFC 6901 JSON pointer of the anchored spec node, e.g. "/definitions/User" or
// "/paths/~1pets/get".
Pointer string
// Pos is the source location (file:line:col) of the producing construct.
Pos token.Position
}
Provenance ties a node in the produced Swagger spec (by RFC 6901 JSON pointer) to the source position of the Go construct that produced it.
It is the source-side half of the cross-ref linker (see the genspec-tui linkage design). Provenance is emitted via Options.OnProvenance only at "anchor" nodes — those born from a code detail (a type declaration, a struct field, a const/var value, a route/meta annotation block).
Finer nodes carry no Provenance of their own; a consumer resolves them to their nearest anchored ancestor.
Experimental: this surface may change while LSP / TUI integration matures.
type ScanCtx ¶
type ScanCtx struct {
// contains filtered or unexported fields
}
func NewScanCtx ¶
func (*ScanCtx) AddDiscoveredModel ¶ added in v0.34.1
func (s *ScanCtx) AddDiscoveredModel(decl *EntityDecl)
AddDiscoveredModel registers decl in the ExtraModels index so the spec orchestrator emits a top-level definition for it.
No-op when decl is already an annotated swagger:model (in Models); annotated decls are emitted unconditionally and re-registering them as "discovered" would create a Models↔ExtraModels bouncing loop in joinExtraModels. Nil and Ident-less decls are silently ignored.
Use only at sites that explicitly intend the registration — pure-read lookups should use GetModel. See [§model-lookup](./README.md#model-lookup).
func (*ScanCtx) BeginDefOrigins ¶ added in v0.35.1
BeginDefOrigins opens a buffering window for the definition keyed by defKey (its fully-qualified EntityDecl.DefKey).
Until [EndDefOrigins], every [RecordOrigin] call is buffered under defKey instead of fired. No-op when no provenance sink is wired. Non-reentrant: each definition is built in its own pass, so windows never nest.
func (*ScanCtx) BeginDeferredOrigins ¶ added in v0.35.1
BeginDeferredOrigins opens a buffering window keyed by key for a top-level spec node that may be pruned after the build (a shared response).
Until [EndDeferredOrigins], every [RecordOrigin] call is buffered under key instead of fired, so it can be dropped wholesale ([DropDeferredOrigins]) if the node is pruned, or flushed verbatim ([FlushDeferredOrigins]) if it survives. No-op when no provenance sink is wired.
Non-reentrant.
func (*ScanCtx) CleanGoDoc ¶ added in v0.35.1
CleanGoDoc reports whether godoc-syntax filtering is enabled (Options.CleanGoDoc).
func (*ScanCtx) DeclForType ¶
func (s *ScanCtx) DeclForType(t types.Type) (*EntityDecl, bool)
func (*ScanCtx) DefaultAllOfForEmbeds ¶ added in v0.35.1
DefaultAllOfForEmbeds reports whether plain struct embeds should render as allOf composition instead of inlined properties (Options.DefaultAllOfForEmbeds).
func (*ScanCtx) DescWithRef ¶
func (*ScanCtx) DropDefOrigins ¶ added in v0.35.1
DropDefOrigins discards the buffered anchors for a definition that has been pruned, so its provenance is never emitted (no orphan pointer into a definition absent from the final document).
func (*ScanCtx) DropDeferredOrigins ¶ added in v0.35.1
DropDeferredOrigins discards the buffered anchors for a deferred node that has been pruned, so its provenance is never emitted (no orphan pointer into a node absent from the final document).
func (*ScanCtx) EmitDiagnostic ¶ added in v0.35.0
func (s *ScanCtx) EmitDiagnostic(d grammar.Diagnostic)
EmitDiagnostic delivers d to the consumer's Options.OnDiagnostic sink, suppressing exact duplicates — same position, code and message — for the lifetime of the scan.
The build re-processes the same field/annotation in several passes (most visibly a swagger:parameters struct applied to multiple operation ids, which rebuilds every field once per id), so the identical diagnostic would otherwise surface once per visit.
The accumulator returned by common.Builder.Diagnostics() is unaffected — only the callback stream dedups.
func (*ScanCtx) EmitHierarchicalNames ¶ added in v0.35.0
EmitHierarchicalNames reports whether the caller opted into the hierarchical fail-safe for over-budget collision groups.
func (*ScanCtx) EmitRefSiblings ¶ added in v0.35.0
func (*ScanCtx) EmitXGoType ¶ added in v0.35.0
func (*ScanCtx) EndDefOrigins ¶ added in v0.35.1
func (s *ScanCtx) EndDefOrigins()
EndDefOrigins closes the current definition buffering window.
func (*ScanCtx) EndDeferredOrigins ¶ added in v0.35.1
func (s *ScanCtx) EndDeferredOrigins()
EndDeferredOrigins closes the current deferred buffering window.
func (*ScanCtx) ExtraModels ¶
func (*ScanCtx) FileForPos ¶ added in v0.35.0
FileForPos returns the *ast.File in package pkgPath whose source interval contains pos.
Used when a struct's fields are defined in a different file than the decl that carries them — e.g. embedding a cross-package defined type (`type AnotherPackageAlias color.Color`), where the promoted fields live in the underlying type's source file, not in the embedding type's file. See go-swagger#2417.
Matching is done via the shared FileSet: positions and ast.File starts resolve through the same *token.File, so the comparison is independent of go/ast's File range accessors.
func (*ScanCtx) FileSet ¶ added in v0.34.1
FileSet returns the shared *token.FileSet used by the scan's loaded packages.
Callers that construct a grammar.Parser for comment groups not owned by a single EntityDecl's *packages.Package (notably operation and route path-level annotations aggregated across packages) read the FileSet from here so the produced positions resolve against the same file table the rest of the scan uses.
func (*ScanCtx) FindComments ¶
func (*ScanCtx) FindEnumValues ¶
func (s *ScanCtx) FindEnumValues(pkg *packages.Package, enumName string) (list []any, descList []string, posList []token.Pos, _ bool)
FindEnumValues returns the enum values, per-value descriptions and per-value source positions for the constants typed enumName, plus ok.
The positions are parallel to the values (one token.Pos per value, the const identifier) and feed the cross-ref /…/enum/{i} anchors; callers that don't need them ignore the third result.
func (*ScanCtx) FindModel
deprecated
func (s *ScanCtx) FindModel(pkgPath, name string) (*EntityDecl, bool)
FindModel returns the model decl for (pkgPath, name) and, when the hit comes from FindDecl fallback, registers it in ExtraModels as a side effect.
Deprecated: prefer the explicit pair GetModel (pure read) and AddDiscoveredModel (explicit registration).
The implicit registration side effect surprises readers and pulls stdlib types (notably time.Time, json.RawMessage) into the spec's top-level definitions when they should be inlined where referenced. See [§model-lookup](./README.md#model-lookup).
func (*ScanCtx) FindModelsByLeaf ¶ added in v0.35.0
func (s *ScanCtx) FindModelsByLeaf(name string) []*EntityDecl
FindModelsByLeaf returns every annotated swagger:model whose Go type name equals name, across all scanned packages, sorted by package path for determinism.
It is the build-time analogue of the reduce stage's resolveDefinitionByLeaf: the type-name keyword sites use it to resolve a bare leaf to a model declared in another package (unique -> promote; several -> ambiguous).
Only the annotated model set (fixed before building) is searched — not the discovery-grown ExtraModels — so the result is a pure function of the source, independent of build order (W6).
func (*ScanCtx) FlushDefOrigins ¶ added in v0.35.1
FlushDefOrigins fires every buffered definition anchor, re-pointing each from its build-time fully-qualified base (#/definitions/<defKey>) to the definition's final name. finalName maps a definition key to the name the spec emits for it (identity when unchanged).
Pointers are emitted in a deterministic (sorted) order. After the flush the buffer is cleared.
func (*ScanCtx) FlushDeferredOrigins ¶ added in v0.35.1
func (s *ScanCtx) FlushDeferredOrigins()
FlushDeferredOrigins fires every still-buffered deferred anchor verbatim (the nodes are never renamed) in a deterministic order, then clears the buffer.
func (*ScanCtx) GetModel ¶ added in v0.34.1
func (s *ScanCtx) GetModel(pkgPath, name string) (*EntityDecl, bool)
GetModel is a pure read: it returns the model decl for (pkgPath, name) without any side effect.
Details ¶
See [§model-lookup](./README.md#model-lookup) — the three-source lookup order (Models, ExtraModels, FindDecl), and how this differs from FindModel.
Returns (nil, false) when no matching decl exists in any of the three sources. Callers that want the lookup hit registered as a discovered model must follow up with AddDiscoveredModel explicitly.
func (*ScanCtx) Mangler ¶ added in v0.35.1
func (s *ScanCtx) Mangler() *mangling.NameMangler
Mangler returns the scan's shared name mangler (swag-style name transforms).
func (*ScanCtx) MoveExtraToModel ¶
func (*ScanCtx) NameConcatBudget ¶ added in v0.35.0
NameConcatBudget returns the caller-supplied readability budget for collision-deconflicted definition names, or 0 when unset — the spec builder substitutes its built-in default in that case.
func (*ScanCtx) NameFromTags ¶ added in v0.35.1
NameFromTags returns the ordered list of struct-tag types consulted to derive a field's emitted name.
A nil/unset option defaults to ["json"] (the historic behaviour); an explicit empty slice means no tag is consulted and names fall back to the Go field name.
func (*ScanCtx) NumExtraModels ¶
func (*ScanCtx) OnDiagnostic ¶ added in v0.34.1
func (s *ScanCtx) OnDiagnostic() func(grammar.Diagnostic)
OnDiagnostic returns the user-supplied diagnostic sink, or nil when the consumer has not opted into diagnostic delivery.
Details ¶
See [§diagnostics](./README.md#diagnostics) — callback contract, ordering guarantee, experimental-API caveat.
func (*ScanCtx) Operations ¶
func (s *ScanCtx) Operations() iter.Seq[parsers.ParsedPathContent]
func (*ScanCtx) OriginEnabled ¶ added in v0.35.0
OriginEnabled reports whether a provenance sink is wired, so callers can skip JSON-pointer construction entirely when no consumer is listening.
func (*ScanCtx) ParamOrigin ¶ added in v0.35.0
ParamOrigin returns the captured source position for parameter name on operation opID, recorded earlier via [RecordParamOrigin].
The spec builder's deferred pass uses it to emit /paths/{path}/{method}/parameters/{i} anchors once the final path binding and array index are known.
func (*ScanCtx) ParameterRefs ¶ added in v0.35.1
func (s *ScanCtx) ParameterRefs() iter.Seq[*ParameterRef]
ParameterRefs iterates the standalone `swagger:parameters` reference markers discovered on func declarations (the references that wire shared parameters into operations / path-items as $refs).
See ParameterRef.
func (*ScanCtx) Parameters ¶
func (s *ScanCtx) Parameters() iter.Seq[*EntityDecl]
func (*ScanCtx) PosOf ¶ added in v0.34.1
PosOf resolves p to a token.Position via the active FileSet.
Returns the zero token.Position when p is invalid or no FileSet is available. Useful for attaching a source location to a Diagnostic without each caller re-deriving the FileSet.
func (*ScanCtx) PruneUnusedModels ¶ added in v0.35.1
PruneUnusedModels reports whether the caller opted into pruning discovered definitions that are not transitively referenced from a root (paths, shared responses/parameters, overlay definitions).
func (*ScanCtx) RecordOrigin ¶ added in v0.35.0
RecordOrigin fires the consumer's Options.OnProvenance callback for one anchor node, when wired.
Unlike diagnostics it accumulates nothing — the cross-ref index is owned by the consumer (see the genspec-tui linkage design).
Exception: while a definition build is in progress (between [BeginDefOrigins] and [EndDefOrigins]) the anchor is buffered instead of fired, so it can be re-pointed to the definition's final name — or dropped if the definition is pruned — by [FlushDefOrigins] at the end of the build.
Anchors outside a definition build (paths, responses, info, parameters) fire inline as before; name reduction never renames those.
func (*ScanCtx) RecordParamOrigin ¶ added in v0.35.0
RecordParamOrigin stashes the source position of one parameter field, keyed by the operation id it applies to and the parameter name, for deferred anchor emission.
No-op when no provenance sink is wired. See [ParamOrigin].
func (*ScanCtx) RefAliases ¶
func (*ScanCtx) SetXNullableForPointers ¶
func (*ScanCtx) SingleLineCommentAsDescription ¶ added in v0.35.0
func (*ScanCtx) SkipAllOfCompounding ¶ added in v0.35.0
func (*ScanCtx) SkipEnumDescriptions ¶ added in v0.35.0
func (*ScanCtx) SkipExtensions ¶
func (*ScanCtx) SkipJSONifyInterfaceMethods ¶ added in v0.35.1
SkipJSONifyInterfaceMethods reports whether the interface-method auto-jsonify mangler is disabled (Options.SkipJSONifyInterfaceMethods).
A `swagger:name` override is honored verbatim regardless.
func (*ScanCtx) SourcelessPackage ¶ added in v0.36.4
SourcelessPackage reports whether a package's types arrived without its source, and why.
The distinction a builder needs when a declaration lookup comes back empty. Empty because the load deliberately did not read that package is an expected outcome of a chosen strategy; empty for any other reason means the graph is not what it claims to be, and the builders keep failing on that — turning a broken load into a quietly thinner document would be the worse trade.
Always false under an ordinary scan, where every package is read from source.
func (*ScanCtx) TransparentAliases ¶
type TypeIndex ¶
type TypeIndex struct {
AllPackages map[string]*packages.Package
Models map[*ast.Ident]*EntityDecl
ExtraModels map[*ast.Ident]*EntityDecl
Meta []*ast.CommentGroup
Routes []parsers.ParsedPathContent
Operations []parsers.ParsedPathContent
Parameters []*EntityDecl
ParameterRefs []*ParameterRef
Responses []*EntityDecl
// contains filtered or unexported fields
}
func NewTypeIndex ¶
func NewTypeIndex(pkgs []*packages.Package, opts ...TypeIndexOption) (*TypeIndex, error)
type TypeIndexOption ¶
type TypeIndexOption func(*TypeIndex)
func WithAfterDeclComments ¶ added in v0.35.1
func WithAfterDeclComments(enabled bool) TypeIndexOption
WithAfterDeclComments enables folding a declaration's inside-body leading comment (struct) or trailing comment (alias / non-struct type) into the decl's annotation source.
See Options.AfterDeclComments.
func WithExcludeDeps ¶
func WithExcludeDeps(excluded bool) TypeIndexOption
func WithExcludePkgs ¶
func WithExcludePkgs(excluded []string) TypeIndexOption
func WithExcludeTags ¶
func WithExcludeTags(excluded map[string]bool) TypeIndexOption
func WithIncludePkgs ¶
func WithIncludePkgs(included []string) TypeIndexOption
func WithIncludeTags ¶
func WithIncludeTags(included map[string]bool) TypeIndexOption
func WithOnDiagnostic ¶ added in v0.35.0
func WithOnDiagnostic(cb func(grammar.Diagnostic)) TypeIndexOption
WithOnDiagnostic wires the consumer's diagnostic sink so the index can surface scan-environment observations (e.g. a package or route omitted by the caller's own include/exclude rules) as informational Hints.
The index is built before the ScanCtx exists, so it reports through the raw callback directly, exactly as detectDegradedLoad does.
func WithRefAliases ¶
func WithRefAliases(enabled bool) TypeIndexOption
func WithTransparentAliases ¶
func WithTransparentAliases(enabled bool) TypeIndexOption
func WithXNullableForPointers ¶
func WithXNullableForPointers(enabled bool) TypeIndexOption
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package classify provides small classification predicates used by the scanner and by builders to decide whether a given name or comment line belongs to a particular Swagger-annotation family.
|
Package classify provides small classification predicates used by the scanner and by builders to decide whether a given name or comment line belongs to a particular Swagger-annotation family. |