| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Introduce `ComponentNames`, the configuration surface for renaming the fixed, spec-independent package-level identifiers oapi-codegen emits (`ServerInterface`, `Client`, `GetSwagger`, the parameter-binding error types, ...). This commit adds the struct, the three-layer resolution (defaults -> prefix -> explicit overrides, then family derivation from the resolved roots) and validation; the templates still hardcode their names and are converted in follow-ups, so generated output is unchanged. Resolution happens once in Generate and fills the struct in place, the same way `client-type-name` has always been defaulted. Unexported names (`swaggerSpec`, `rawSpec`, `decodeSpec`, `decodeSpecCached`, `strictHandler`) lower the prefix's first letter so they stay unexported, which is what makes emitting two specs into one Go package a one-line fix. `client-type-name` is generalized rather than duplicated: it keeps its narrow meaning (rename only the client struct) for backwards compatibility, while `component-names.client` is the root that renames the whole client family. Setting both to different values is a validation error. Validation covers Go-identifier legality of every supplied name, the prefix having to start with a letter, and pairwise uniqueness of the resolved names. Uniqueness is checked over the names a config actually emits, gated by `generate`, so disabling a generator cannot produce a spurious clash. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t-type-name Two amendments to the resolution model: The prefix is now prepended to every resolved name, an explicit override included, rather than only to names still at their default. Prefix is independent of the overrides: it affects everything or nothing. So `prefix: PetStore` with `client: MyClient` resolves to `PetStoreMyClient`, and the client family derives from that prefixed root. The unexported-name rule is unchanged: the prefix's first letter is lowered so `swaggerSpec` & friends stay unexported. `client-type-name` is deprecated rather than conflicting. When it and `component-names.client` are both set, `component-names.client` wins and Configuration.Warnings reports the shadowing; on its own it keeps seeding the client name exactly as before, renaming the struct and nothing else. ClientStem records the name the client family derives from, which differs from Client only under the deprecated knob. Templates use it for prose about the family as a whole, so that prose stays consistent with the family's names instead of drifting to the struct's. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…plates Replace the hardcoded client-family identifiers in client.tmpl and client-with-responses.tmpl with the resolved component names, doc comments included. The `client-type-name` interpolation that these templates already carried is unified with the new mechanism rather than layered on top of it: `$clientTypeName` now reads `names.Client`, which is where the legacy knob lands after resolution. Output is unchanged for every existing configuration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…plates Replace the hardcoded identifiers in the shared net/http skeletons (server-interface, server-middleware, server-handler), the chi and gorilla hooks, and the echo/gin/fiber/iris templates with the resolved component names: ServerInterface and its wrapper, MiddlewareFunc, the Handler and RegisterHandlers families, Unimplemented, ServeMux, EchoRouter, the per-framework *ServerOptions structs, and the six parameter-binding error types -- at their declarations, at every use site, and in the doc comments that name them. Note that echo declares no MiddlewareFunc of its own (it uses echo.MiddlewareFunc), so that name is dropped from echo's emitted set. The only change to generated output is a typo in one iris doc comment: `IrisServerOption` was missing its trailing `s`, and interpolating the type name necessarily corrects it. Every other fixture is byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… names
Completes the template conversion:
- strict server: StrictServerInterface, StrictHandlerFunc,
StrictMiddlewareFunc, NewStrictHandler(WithOptions), the unexported
strictHandler and the Strict{HTTP,Gin}ServerOptions structs, across all
five per-framework strict templates.
- embedded spec: GetSwagger, GetSpec, GetSpecJSON, PathToRawSpec and the
unexported swaggerSpec, rawSpec, decodeSpec and decodeSpecCached, whose
prefixed forms are what let two specs share a Go package.
- webhook/callback initiators and receivers, whose Webhook/Callback prefix
now composes with the component prefix rather than competing with it:
the component prefix goes in front of the existing one, after the New/With
verb, matching how New<Client> is derived.
The one place that keeps a hardcoded name is the import-mapping call
`<pkg>.PathToRawSpec` in inline.tmpl. That name belongs to the referenced
package, whose component-names config this config cannot see, so the
default is the only defensible choice; a comment records why.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Component names are declared by the templates, never by a TypeDefinition, so the duplicate-typename check in GenerateTypes could not see them: a spec with `components/schemas/Client` silently emitted two `Client` declarations and failed at `go build` with no clue where the second one came from. Fold the resolved component names into that check and report the collision with both remedies -- x-go-name on the schema, or component-names (or its prefix) on the component. Only the names the configuration actually declares are reserved, so a schema called `Client` in a models-only config is still fine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two configurations generate from one spec into a single Go package, each with its own `component-names.prefix` -- the multi-spec-one-package case the prefix exists for, and only possible because the prefix renames the unexported swaggerSpec, rawSpec, decodeSpec, decodeSpecCached and strictHandler too. Between them the runs declare every fixed name the templates can emit: models, client, std-http server, strict server and embedded spec under `PetStore` (with root overrides for the client, server interface, strict server interface, handler and spec accessors, an error-type rename, and the stdhttp serve-mux group), and a chi server with a renamed Unimplemented under `Admin`. The committed .gen.go files are the stale-literal detector: a name a template still hardcodes either fails to compile as an undefined identifier or is redeclared across the two runs. The smoke test drives the renamed client against the renamed strict server, asserts the renamed error type is what the wrapper hands to ErrorHandlerFunc, and loads both embedded specs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the configuration-schema.json entry (editor-only, but kept at parity with the Go structs) and a README section covering the three reasons to rename -- schema collisions, two specs in one package, house style -- the uniform prefix rule including the unexported-name casing, the table of roots and what derives from each, the prefix-only remainder, and the two collision errors. Also cross-reference it from the single-package import-mapping section, which is where readers hit the two-specs-one-package problem, and mark `client-type-name` deprecated in the schema description and in the custom-client-type example, which is kept as-is to pin that option's behaviour. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two client knobs were competing: `component-names.client` won and the deprecated `client-type-name` was ignored whenever both were set. They now control different things. `component-names.client` is the family root -- folded in before derivation, so it names ClientInterface, NewClient, ClientWithResponses and the rest, and, absent the deprecated knob, the struct too. `client-type-name` is a struct-name override applied after derivation: it renames the client struct and nothing else, exactly as it always has. Setting both is now legitimate rather than half-ignored. The struct takes the legacy name while the family derives from the root, so `client-type-name: George` with `client: APIClient` yields `NewAPIClient() (*George, error)` -- mixed naming, but coherent, and the migration path for a codebase whose callers still spell the old struct name. Warnings describes the mix instead of reporting a shadowed knob. The override still lands before the uniqueness check, so a `client-type-name` colliding with a name derived from the root is caught as a configuration error rather than a compile error. Generated output is unchanged for every existing configuration: with `client-type-name` alone -- the only form in the wild -- the family stays at its defaults exactly as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ClientStem existed to serve a single doc comment: the client family root, which differs from the client struct's name only when the deprecated `client-type-name` overrides the struct. No derived field renders the bare root -- they all carry a suffix or a New prefix -- so the comment could not be written against the materialized fields. Trade the field for a slightly imprecise comment. The family now derives directly from cn.Client inside resolve(), which still runs before resolveComponentNames applies `client-type-name` on top, so the orthogonal semantics are untouched: the deprecated knob renames the emitted struct and nothing else, and the George/APIClient and collision cases behave exactly as before. Behavior delta, deliberate and narrowly scoped to one doc comment: with `client-type-name` set, the comment on the ClientWithResponses constructor now names the struct rather than the family, reading "wraps APIClient" where it used to read "wraps Client". That renames one line in each of the two fixtures that exercise the deprecated knob -- examples/custom-client-type and internal/test/schemas/deprecated -- and nothing else. Under the defaults and under `component-names.client` the rendered text is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The import-mapping call `<pkg>.PathToRawSpec` was left at the default name on the reasoning that it belongs to the referenced package, whose config we cannot see. That made renaming it a documented limitation, and made a mismatch fail silently in the sense that the call compiled only by luck -- it linked when the referenced package happened not to rename anything. Resolve it from the referencing config instead, the same field the declaration uses. With consistent settings it links; with mismatched settings it fails loudly at compile time (`undefined: externalRef0.ZzPathToRawSpec`) rather than quietly depending on one side having left the name alone. That turns the limitation into a requirement, documented alongside the component-names reference and styled after the existing strict-server import-mapping constraint: specs that reference each other through import-mapping must share their component-names settings, prefix included. The rationale is in the passage too -- import-mapping splits the boilerplate of what is conceptually one spec across packages, so the pieces should be generated consistently, with x-go-name / x-go-type left as the per-schema escape hatch if individual names must diverge. No change to generated output: under default settings the resolved name is the default, so every import-mapping fixture is byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Greptile SummaryThis PR adds configurable names and prefixes for fixed generated identifiers, updates templates across supported clients and server backends, and adds schema-to-component collision diagnostics.
Confidence Score: 4/5The PR should not merge until webhook and callback component declarations participate in collision detection, otherwise valid-looking generation can still produce uncompilable Go. The new collision mechanism omits package-level event-family declarations that are emitted for realistic webhook and callback specs, leaving schema-name collisions undiagnosed and producing duplicate Go declarations. Files Needing Attention: pkg/codegen/component_names.go, pkg/codegen/templates/initiator.tmpl, pkg/codegen/templates/receiver-stdlib.tmpl Important Files Changed
### Issue 1
pkg/codegen/component_names.go:396-399
**Event component collisions remain undetected**
When models and webhook or callback client/server code are generated together, schemas such as `WebhookInitiator` or `WebhookReceiverInterface` are not checked against the corresponding template-generated declarations, causing duplicate package-level identifiers that downstream `go build` rejects.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "feat(templates): resolve PathToRawSpec a..." | Re-trigger Greptile |
Sorry, something went wrong.
…ll site The field comment still described the pre-resolution behavior (cross-package callers using the default name because the referenced config is unknowable). Since the call site interpolates the referencing config's own resolved name, the accurate statement is the documented constraint: import-mapped configs must share component-names settings, and mismatches fail to compile. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| "properties": { | ||
| "required-param-error": { | ||
| "type": "string", | ||
| "description": "Default `RequiredParamError`" |
There was a problem hiding this comment.
Can we use ie
| "description": "Default `RequiredParamError`" | |
| "default": "RequiredParamError" |
Or does this mean "the default for the RequiredParamError's value?
Sorry, something went wrong.
There was a problem hiding this comment.
I'd love if we could start using the JSON Schema as the source of truth for things like defaults ie through code generation
Would keep things more in sync going forward but might not quite be what we want here
Also, this sort of customisation may be quite cumbersome as folks use multiple import mappings (if they have to define these in multiple places) so we may want to look at adding a way to reuse config across files
Also possibly related - #1920
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Add output-options.component-names: configurable names for all fixed generated identifiers
oapi-codegen emits a set of package-level identifiers whose names are fixed and
spec-independent: ServerInterface, Client, GetSwagger, RegisterHandlers,
the parameter-binding error types, and ~40 more. Until now they could not be
renamed (except the client struct, via client-type-name). That causes two real
problems with no escape hatch:
RequiredParamError, …) generates two declarations of the same name. Nothing
detected this; the output simply didn't compile.
package — every fixed name collides, including unexported ones
(swaggerSpec, decodeSpec, …).
This PR adds output-options.component-names: a prefix that decorates every
fixed name, plus individual overrides for the names users most plausibly need to
control. It also adds generation-time collision detection between schema names
and component names.
With no component-names configured, output is byte-identical to before, with
two deliberate exceptions listed under Behavior deltas.
Usage
Emitting two specs into one package is the flagship use case and needs only the
prefix:
→ PetStoreServerInterface / AdminServerInterface, PetStoreGetSwagger /
AdminGetSwagger, petStoreSwaggerSpec / adminSwaggerSpec, and so on — no
collisions, one package.
Configuration reference
20 keys, all optional. Root keys rename a family: derived names follow
automatically. Names without a key are still covered by prefix.
Prefix-only names (no individual key): RequestEditorFn, HttpRequestDoer,
WithHTTPClient/WithBaseURL/WithRequestEditorFn, StrictHandlerFunc,
StrictMiddlewareFunc, NewStrictHandler(WithOptions), the per-framework
*ServerOptions structs, PathToRawSpec, the unexported spec machinery
(swaggerSpec, rawSpec, decodeSpec, decodeSpecCached, strictHandler),
and the webhook/callback initiator/receiver families.
Resolution semantics
Resolved once per generation, in three layers:
(prefix: PetStore + client: MyClient → PetStoreMyClient). The prefix
is uniform and independent: it affects everything or nothing.
Family derivation happens after prefixing, from the resolved root — so each
derived name carries the prefix exactly once (NewPetStoreMyClient).
Unexported names take the prefix with its first letter lowered
(petStoreSwaggerSpec), preserving unexportedness.
Validation (config-load time): every supplied name must be a valid Go
identifier; the prefix must start with a letter; the resolved names of the
generators actually enabled must be pairwise distinct.
client-type-name is deprecated
The two knobs are orthogonal, which preserves the legacy knob's historical
behavior exactly:
and everything derived from it.
Set alone, each behaves as documented above. Set together, the struct takes the
legacy name while the family derives from the root — client-type-name: George
breaks, a warning describes the mixed naming, and removing the deprecated knob
is the fix.
Collision detection
Component names now participate in duplicate-name checking. A schema that
resolves to the same identifier as a component (e.g. a schema named Client)
fails generation with a message naming both remedies: x-go-name on the
schema, or component-names/prefix on the component. Previously this
produced uncompilable output with no diagnostic.
Import-mapping
Specs that reference each other via import-mapping must be generated with the
same component-names settings (prefix included). Import-mapping splits what
is conceptually one spec's boilerplate across packages; the pieces are one API
and should be generated consistently. The cross-package PathToRawSpec call
site interpolates the referencing config's resolved name, so consistent
settings just work and mismatched settings fail to compile with an undefined
error. Per-schema x-go-name/x-go-type remain the escape hatch if individual
names truly must diverge. (Documented in the README alongside the analogous
strict-server constraint.)
Behavior deltas (deliberate, visible in fixtures)
its trailing s; interpolating the type name necessarily fixes the typo.
NewClientWithResponses comment now names the configured client type
(e.g. "wraps APIClient") instead of the literal word Client.
Every other pre-existing fixture is byte-identical.
Design notes
naming decisions. Doc comments and error-message strings interpolate too.
(NewPetStoreClient — verb first, from derivation) and prefix-only names
(PetStoreNewStrictHandler — prefix first). Unifying this was considered
and rejected: all names are unique either way, and the special-casing isn't
worth the generator complexity.
forever; adding keys later is cheap, removing them impossible).
Testing
uniqueness and identifier validation, legacy-knob orthogonality (including
the both-set case asserted through full Generate() output), and
legacy-name-vs-derived-name collisions.
from one spec into one package (PetStore + Admin prefixes, root
overrides, error rename, framework group), committed output, compile + smoke
test. This fixture doubles as the stale-literal detector: a missed hardcoded
name fails compilation.
unprefixed names + build), plus webhook and callback specs.
component makes it generate).
🤖 Generated with Claude Code