godoclink

package
v0.36.3 Latest Latest
Warning

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

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

README

This document is the long-form companion to the godoclink package.

godoclink implements the Options.CleanGoDoc feature: when a title / description is carried from a Go doc comment into the emitted spec, it cleans godoc-specific syntax that reads as bracket noise, and recomposes resolvable doc-links to the name the referenced schema is actually exposed under.

It is applied only to godoc-derived prose — never to author-written swagger:title / swagger:description overrides, which flow through a separate path (common.Builder.HarvestOverrides) and are deliberate.

The recognizer regexes are adapted from github.com/fredbi/go-fred-mcp/pkg/doc-filters/godoc-filter; the key difference is that this package rewrites the prose, whereas that tool redacts (length-preserving blanking) for masking.


Table of contents

  • §transforms — what is cleaned, and the recognizer
  • §seam — why recomposition is split across two build phases
  • §markers — the marker format and the round-trip contract
  • §wiring — how builders call in, and the consumption sites
  • §deferred — intentionally-deferred follow-ups

§transforms — what is cleaned

With CleanGoDoc on, godoc-derived prose is run through Clean:

  1. Reference-definition lines dropped — a line like [text]: https://… (optionally indented) is godoc/markdown link plumbing carrying no prose; the whole line is removed and the blank run it leaves is folded.
  2. Doc-link spans rewritten[Widget], [pkg.Type], [Order.Field] (a leading * tolerated). The brackets are stripped and the span replaced by either the referenced schema's exposed name (see §seam) or, when it does not resolve, the humanized leaf identifier (mangling.NameMangler.ToHumanNameLower, e.g. [CustName] → "cust name").
  3. Leading self-name recomposed — a declaration's godoc conventionally opens with its own name (// Widget does things). With a SelfRef, that leading word is recomposed to the decl's own exposed name.
  4. Sentence-initial titleizing — the first identifier of the prose is restored to sentence case (first rune upper), whatever the exposed name's actual case (Widget+swagger:model gizmo → "Gizmo …").

Conservative recognizer. docLinkRE matches only a dotted chain ([pkg.Type]) or an uppercase-led single ([Widget]). Ordinary prose brackets are left intact by construction: []byte (empty), [0] (digit-led), [see notes] (spaces), bare-lowercase [id] (a lowercase single never names an exported schema in this phase).

§seam — the two-phase split

Recomposition has two halves that want opposite timing:

  • Which prose is godoc-derived is known only here, at the consumption seam — block.PreambleTitle/PreambleDescription/Prose() are godoc, while overrides arrive via HarvestOverrides. After the build, a description is just a string; provenance is gone. So cleaning must happen at consumption.
  • A referenced schema's final exposed name is fixed only by the spec builder's reduceDefinitionNames(), which runs last (collision renames shorten the fully-qualified discovery keys). So the final name is unknown at consumption.

The bridge: at consumption a resolvable doc-link is replaced by a marker carrying the referenced type's fully-qualified definition key; a post-reduce pass (spec.Builder.substituteGodocMarkersSubstituteMarkers) rewrites each marker to the final name. This mirrors the existing defOrigins → FlushDefOrigins(finalName) pattern in the scanner: buffer keyed by fq-key during the build, re-point to final names after reduce.

§markers — format and round-trip

A marker is NUL / Unit-Separator delimited — neither rune can occur in a Go source comment, so a marker never collides with real prose:

\x00gl\x1f<defKey>\x1f<suffix>\x1f<fallback>\x1f<0|1>\x00
  • defKey — the referenced type's fully-qualified definition key (the same key EntityDecl.DefKey() produces, so swagger:model overrides are honored).
  • suffix — the exposed field-chain for a member reference (.customer_name), or empty for a bare type.
  • fallback — the humanized leaf, used when the key turns out not to be an emitted definition (pruned / unresolved).
  • titleize bit — sentence-initial position.

SubstituteMarkers(text, finalName) resolves each marker: finalName+suffix when finalName(defKey) succeeds, else fallback; the titleize bit upper-cases the first rune. It guarantees no marker survives — an unmatched marker collapses to its fallback. With CleanGoDoc off no marker is ever produced, and SubstituteMarkers short-circuits on marker-free text (HasMarkers).

The round-trip (emit via Clean with a ResolverSubstituteMarkers, including the pruned-key fallback and a collision rename) is unit-tested in markers_test.go.

§wiring — how builders call in

Clean(text, Options{Mangler, Resolver, Self}). The two callers are on the builder side, gated by Ctx.CleanGoDoc():

  • common.Builder.CleanGoDoc / CleanGoDocSelf (the latter passes a Self, used for a declaration's title/description; the former for field / member prose). common.Builder.godocResolver builds the Resolver from the active EntityDecl (reusing ScanCtx.GetModel; same-package + imported lookup; field → exposed property name via resolvers.ParseFieldTag + NameFromTags).
  • spec.Builder.cleanGoDoc — a sibling for the swagger:meta Info site (the spec builder does not embed common.Builder); resolution-free there (info prose rarely names models).

The nine godoc-prose consumption sites it is wired at: swagger:meta Info title/description; route + inline operation summary/description; response and response-header description; parameter description; model title/description; field description (plain and $ref-override paths).

A nil Resolver (or nil Self) selects resolution-free cleanup — the behavior for sites without a usable decl context.

§deferred — follow-ups

  • Field-level leading self-name. Only a declaration's own leading name is recomposed; a field's leading Go name (// Holder …) is left as-is.
  • Nested member chains. [Type.A.B] resolves only the first member level; deeper chains fall back to humanizing the leaf.
  • Dot-imports. A .-imported package is skipped in import resolution, so a [Type] actually referring to a dot-imported schema is humanized.

None of these is wrong today — each falls back to the humanized leaf.

Documentation

Overview

Package godoclink rewrites godoc-specific syntax.

It rewrites comments that read as noise when a Go doc comment is carried into a Swagger title / description (corresponds to the Options.CleanGoDoc feature).

Two transforms apply to godoc-derived prose:

  • resolution-free cleanup: reference-style link definition lines (`[text]: url`) are dropped; godoc doc-link spans (`[Widget]`, `[pkg.Type]`, `[Order.Field]`) have their brackets removed and the (leaf) identifier humanized via the swag name mangler — e.g. `[CustName]` → "cust name"; the first identifier of the prose is restored to sentence case;
  • idiom recomposition: when a Resolver maps a doc-link (or the leading godoc-convention self-name) to an emitted schema, the span is replaced by a [marker] carrying that schema's fully-qualified definition key. Markers are resolved to the schema's final exposed name by SubstituteMarkers, run after the spec builder has reduced definition names. This two-step dance is needed because the final name is only known at the very end of the build, whereas which prose is godoc-derived is only known here, at the consumption seam.

With a nil Options.Resolver (and nil Self), only the resolution-free cleanup runs and no marker is produced.

The recognizer regexes are adapted from the battle-tested github.com/fredbi/go-fred-mcp/pkg/doc-filters/godoc-filter; the key difference is that this package *rewrites* the prose whereas that tool *redacts* (length-preserving blanking) for masking.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Clean

func Clean(text string, o Options) string

Clean applies godoc filtering to text.

It is the caller's responsibility to apply Clean ONLY to godoc-derived prose — never to author-written swagger:title / swagger:description override text.

Clean never mutates o.

func HasMarkers

func HasMarkers(s string) bool

HasMarkers reports whether s contains any godoclink marker — a cheap guard so callers can skip the substitution walk for marker-free prose.

func SubstituteMarkers

func SubstituteMarkers(text string, finalName func(defKey string) (string, bool)) string

SubstituteMarkers rewrites every marker in text to its final exposed name. finalName maps a definition key to the name it is ultimately emitted under, returning ok=false when the key is not an emitted definition (pruned or unresolved); in that case the marker collapses to its humanized fallback.

A resolved marker yields finalName+suffix. The sentence-initial bit, when set, upper-cases the first rune of the result. No marker ever survives this pass.

Types

type Options

type Options struct {
	// Mangler humanizes leaf identifiers (and marker fallbacks).
	//
	// Required.
	Mangler *mangling.NameMangler
	// Resolver, when non-nil, recomposes resolvable doc-links into markers; nil selects resolution-free cleanup only.
	Resolver Resolver
	// Self, when non-nil, enables leading self-name recomposition.
	//
	// It has effect only together with a non-nil Resolver.
	Self *SelfRef
}

Options configures Clean.

type Resolution

type Resolution struct {
	DefKey string
	Suffix string
}

Resolution is the outcome of resolving a doc-link reference to an emitted schema.

DefKey is the referenced type's fully-qualified definition key (whose final exposed name is substituted later); Suffix is the already-exposed field chain for a dotted member reference (e.g. ".customer_name"), or "" for a bare type reference.

type Resolver

type Resolver func(ref string) (Resolution, bool)

Resolver maps a doc-link reference — the bracket content with any leading `*` stripped, e.g. "Order.CustName" or "pkg.Type" — to a Resolution.

It returns ok=false when the reference does not resolve to an emitted schema, in which case the caller humanizes the leaf identifier instead.

type SelfRef

type SelfRef struct {
	Name   string
	DefKey string
}

SelfRef describes the declaration whose godoc is being cleaned, so the leading godoc-convention self-name ("Widget" in "Widget does things") can be recomposed to the declaration's own exposed name.

Name is the Go identifier; DefKey is its fully-qualified definition key.

Jump to

Keyboard shortcuts

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