scanner

package
v0.35.0 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

scanner — maintainer notes

This document is the long-form companion to the scanner package code. The source files keep godoc concise; complex invariants, design trade-offs, and known quirks live here.

The scanner package owns package loading and entity discovery. It turns a set of Go package patterns into a ScanCtx that exposes the classified per-decl inventory (meta, routes, operations, models, parameters, responses) consumed by the builder layer.


Table of contents

  • §optionsOptions.DescWithRef shape and rationale
  • §descwithref — the description-only-decoration $ref shape and why it has a flag
  • §diagnosticsOnDiagnostic contract and experimental-API caveat
  • §model-lookupGetModel vs FindModel — pure read vs implicit registration
  • §classifierdetectNodes bitmask semantics and struct-annotation exclusivity
  • §quirks-open — deferred follow-ups

§options — Options overview

Options is the externally-visible configuration struct. It is re-exported from the package root as codescan.Options. The default zero value is a valid configuration: every flag defaults to false and every slice/map defaults to nil.

Most fields are simple toggles (scope inclusion, debug, vendor extension suppression). Two fields carry non-trivial semantics that warrant the inline godoc and the deeper notes below:

  • DescWithRef — controls the $ref shape used when a struct field resolves to a named type and its only decoration is a description. See §descwithref.
  • OnDiagnostic — diagnostic callback hook. See §diagnostics.

§descwithref — description-only-decoration $ref shape

When a struct field's Go type resolves to a named type (so the spec emits a $ref to its definition) and its only field-level decoration is a description (no validations, no user-authored vendor extensions), the spec has two possible shapes:

  1. Bare $ref{$ref: ...}. The field's description is dropped. This is the conservative default when DescWithRef is false.
  2. Single-arm allOf{description: "...", allOf: [{$ref}]}. The description is preserved by wrapping the $ref in a single-arm allOf compound. This is JSON-Schema-draft-4 correct for sibling description.

DescWithRef=true opts into the second shape. The default is false because the bare-$ref shape interoperates more broadly with Swagger 2.0 tooling that does not implement the allOf compound.

When the field also carries validation overrides (pattern, enum, example, etc.) or user-authored vendor extensions, the allOf compound is mandatory regardless of DescWithRef — the override would be lost otherwise.

§diagnostics — OnDiagnostic callback

Options.OnDiagnostic, when non-nil, is invoked for every grammar.Diagnostic the builder layer records: lexer/parser warnings, semantic-validation failures from the validations package, and any future diagnostic class wired into the builder pipeline.

Contract:

  • The callback fires once per diagnostic, in source order.
  • Diagnostics never block the build. An invalid construct is silently dropped from the output spec; the explanation flows through this channel instead.
  • The callback may be called from any per-decl builder; it is the caller's responsibility to make it goroutine-safe if the consumer ever drives codescan.Run concurrently (today it is single- goroutine, but the callback contract makes no such guarantee).

The diagnostic surface is experimental. Once the LSP integration matures the shape is expected to grow: typed severity classes, structural deduplication, per-position provenance. Callers that adopt OnDiagnostic today should treat the signature as subject to breaking change in a future minor release.

ScanCtx.OnDiagnostic returns the user-supplied callback verbatim; builders pipe diagnostics through it via common.Builder.RecordDiagnostic.

§model-lookup — GetModel vs FindModel

ScanCtx exposes two lookup helpers with similar signatures but different side-effect contracts. The choice between them is load-bearing for the shape of the emitted spec.

GetModel(pkgPath, name) — pure read

Looks up a model decl across three sources, in order:

  1. Models — decls annotated with swagger:model. Always emitted as top-level definitions regardless of lookup.
  2. ExtraModels — decls discovered as dependencies of other emitted shapes. Already enqueued for top-level emission.
  3. FindDecl — fall through to a syntactic search over the loaded packages.

No side effect. A FindDecl hit through GetModel does not register the decl in ExtraModels. Callers that want the lookup to also surface the decl as a top-level definition must follow up with AddDiscoveredModel explicitly.

FindModel(pkgPath, name) — implicit registration

The older sibling of GetModel. It does the same three-source lookup, but a FindDecl hit also writes the decl into ExtraModels as a side effect.

FindModel is deprecated. The implicit registration 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. Builders that need the registration should use the explicit GetModel + AddDiscoveredModel pair.

AddDiscoveredModel — explicit registration

Registers a decl in ExtraModels. No-op for decls already in Models (annotated decls are emitted unconditionally — registering them as discovered would create a Models↔ExtraModels bouncing loop in the spec orchestrator's joinExtraModels pass). Nil and Ident-less decls are silently ignored, which is defensive against the scanner emitting partial decls during error recovery.

§classifier — detectNodes bitmask

TypeIndex.detectNodes scans every comment group in a file and returns a bitmask of detected annotation kinds. Each kind drives downstream processing:

Bit Annotation Downstream
metaNode swagger:meta file-level meta block
routeNode swagger:route path-level route annotations
operationNode swagger:operation path-level operation annotations
modelNode swagger:model per-decl model registration
parametersNode swagger:parameters per-decl parameter registration
responseNode swagger:response per-decl response registration

route, operation, and meta accumulate freely across comment groups in a file. The three struct-level annotations (model, parameters, response) are mutually exclusive within a single comment group — a struct cannot simultaneously be a model and a parameters bag, for instance. checkStructConflict enforces the rule per comment group and returns an error if the constraint is violated.

The annotation vocabulary recognised by the classifier is a closed set. Unknown annotations beginning with swagger: raise a classifier error. A handful of annotation tokens (strfmt, name, enum, default, alias, type, …) are recognised but produce no bit — they are field-level decorations that downstream builders parse out of the comment block directly.

§quirks-open — deferred follow-ups

  • FindModel deprecation. The deprecated alias is still on the ScanCtx surface for in-tree callers. Once every builder has been audited and migrated to the GetModel + AddDiscoveredModel pair, the deprecated method can be removed in a future major release.
  • Recognised-but-unused annotation tokens. detectNodes recognises a list of field-level tokens (strfmt, name, discriminated, file, enum, default, alias, type, allOf, ignore) only to avoid raising the "unknown annotation" error. Promoting them to per-file bits would let downstream builders skip whole files that carry no decorations — an optimisation, not a correctness change.
  • shouldAcceptTag precedence. When both includeTags and excludeTags are populated, includeTags wins (a tag in includeTags admits the operation even if it also appears in excludeTags). This is deliberate but easy to mis-read; an explicit "the include list takes precedence" doc on Options would help callers, but the field-level prose is already dense.

Documentation

Index

Constants

This section is empty.

Variables

View Source
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.

View Source
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

func JSONPointer(segments ...string) string

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 {
	Comments *ast.CommentGroup
	Type     *types.Named
	Alias    *types.Alias // added to supplement Named, after go1.22
	Ident    *ast.Ident
	Spec     *ast.TypeSpec
	File     *ast.File
	Pkg      *packages.Package
	// contains filtered or unexported fields
}

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. See the name-identity / cyclic-$ref design (.claude/plans/name-identity-cyclic-ref.md §9.1, §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) HasModelAnnotation

func (d *EntityDecl) HasModelAnnotation() bool

func (*EntityDecl) HasParameterAnnotation

func (d *EntityDecl) HasParameterAnnotation() bool

func (*EntityDecl) HasResponseAnnotation

func (d *EntityDecl) HasResponseAnnotation() bool

func (*EntityDecl) ModelOverrideSuppressed added in v0.35.0

func (d *EntityDecl) ModelOverrideSuppressed() bool

ModelOverrideSuppressed reports whether SuppressModelOverride was set.

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

func (d *EntityDecl) OperationIDs() (result []string)

func (*EntityDecl) ResponseNames

func (d *EntityDecl) ResponseNames() (name, goName string)

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. See name-identity design D-4 (.claude/plans/name-identity-cyclic-ref.md §9.1).

type Options

type Options struct {
	Packages                []string
	InputSpec               *spec.Swagger
	ScanModels              bool
	WorkDir                 string
	BuildTags               string
	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

	SkipExtensions bool // skip generating x-go-* vendor extensions in the spec

	// 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

	// 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 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 NewScanCtx(opts *Options) (*ScanCtx, error)

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

func (s *ScanCtx) DeclForType(t types.Type) (*EntityDecl, bool)

func (*ScanCtx) DescWithRef

func (s *ScanCtx) DescWithRef() bool

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

func (s *ScanCtx) EmitHierarchicalNames() bool

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 (s *ScanCtx) EmitRefSiblings() bool

func (*ScanCtx) EmitXGoType added in v0.35.0

func (s *ScanCtx) EmitXGoType() bool

func (*ScanCtx) ExtraModels

func (s *ScanCtx) ExtraModels() iter.Seq2[*ast.Ident, *EntityDecl]

func (*ScanCtx) FileForPos added in v0.35.0

func (s *ScanCtx) FileForPos(pkgPath string, pos token.Pos) (*ast.File, bool)

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

func (s *ScanCtx) FileSet() *token.FileSet

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 (s *ScanCtx) FindComments(pkg *packages.Package, name string) (*ast.CommentGroup, bool)

func (*ScanCtx) FindDecl

func (s *ScanCtx) FindDecl(pkgPath, name string) (*EntityDecl, bool)

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

func (s *ScanCtx) Meta() iter.Seq[*ast.CommentGroup]

func (*ScanCtx) Models

func (s *ScanCtx) Models() iter.Seq2[*ast.Ident, *EntityDecl]

func (*ScanCtx) MoveExtraToModel

func (s *ScanCtx) MoveExtraToModel(k *ast.Ident)

func (*ScanCtx) NameConcatBudget added in v0.35.0

func (s *ScanCtx) NameConcatBudget() float64

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

func (s *ScanCtx) NumExtraModels() int

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

func (s *ScanCtx) OriginEnabled() bool

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

func (s *ScanCtx) ParamOrigin(opID, name string) (token.Position, bool)

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

func (s *ScanCtx) Parameters() iter.Seq[*EntityDecl]

func (*ScanCtx) PkgForType

func (s *ScanCtx) PkgForType(t types.Type) (*packages.Package, bool)

func (*ScanCtx) PosOf added in v0.34.1

func (s *ScanCtx) PosOf(p token.Pos) token.Position

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) RecordOrigin added in v0.35.0

func (s *ScanCtx) RecordOrigin(pointer string, pos token.Position)

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

func (*ScanCtx) RecordParamOrigin added in v0.35.0

func (s *ScanCtx) RecordParamOrigin(opID, name string, pos token.Position)

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 (s *ScanCtx) RefAliases() bool

func (*ScanCtx) Responses

func (s *ScanCtx) Responses() iter.Seq[*EntityDecl]

func (*ScanCtx) Routes

func (s *ScanCtx) Routes() iter.Seq[parsers.ParsedPathContent]

func (*ScanCtx) SetXNullableForPointers

func (s *ScanCtx) SetXNullableForPointers() bool

func (*ScanCtx) SingleLineCommentAsDescription added in v0.35.0

func (s *ScanCtx) SingleLineCommentAsDescription() bool

func (*ScanCtx) SkipAllOfCompounding added in v0.35.0

func (s *ScanCtx) SkipAllOfCompounding() bool

func (*ScanCtx) SkipEnumDescriptions added in v0.35.0

func (s *ScanCtx) SkipEnumDescriptions() bool

func (*ScanCtx) SkipExtensions

func (s *ScanCtx) SkipExtensions() bool

func (*ScanCtx) TransparentAliases

func (s *ScanCtx) TransparentAliases() bool

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

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.

Jump to

Keyboard shortcuts

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