Skip to content

feat: export a companion interface alongside each parameter class#413

Merged
ALagoni97 merged 14 commits into
mainfrom
add_parameter_interface
Jul 15, 2026
Merged

feat: export a companion interface alongside each parameter class#413
ALagoni97 merged 14 commits into
mainfrom
add_parameter_interface

Conversation

@jonaslagoni

Copy link
Copy Markdown
Contributor

What & why

Each generated parameter model now ships a plain-data companion interface alongside the class, and every channel consumer accepts either form. This is the "middle way" between interface-only and class-only: callers can pass a plain object (ergonomic) while the generated channel code still operates on the rich class instance (getChannelWithParameters, serialization, etc.).

// Both are accepted by every generated channel helper:
await http_client.getV2ConnectReferenceId({ server, parameters: { referenceId: 'ref_123' } });          // plain object
await http_client.getV2ConnectReferenceId({ server, parameters: new GetV2ConnectReferenceIdParameters({ referenceId: 'ref_123' }) }); // class

How

Parameter generator (OpenAPI + AsyncAPI):

  • A shared parameterClassPreset factory prepends interface <Name>Interface { ... } above the class, rewrites the constructor to constructor(input: <Name>Interface), and keeps each input's helper methods.
  • The parameters core loop rewrites the trailing export to export { <Name>, <Name>Interface }; (only when the interface is present).
  • buildParametersInterfaceBody skips const properties (matching the ctor input type).

Channel consumers (HTTP + NATS + Kafka + MQTT + AMQP + WebSocket + EventSource):

  • Shared emitters parameterUnionType, parameterInstanceExpression, renderParameterNormalization.
  • addParametersToDependencies imports both <Name> and <Name>Interface.
  • User-input parameter sites accept <Name>Interface | <Name> and normalize to a class instance before use (inline at the topic/URL build site; a parameterInstance local for WebSocket which passes it to callbacks).
  • Callback params and createFromChannel-built instances stay class-typed.

Breaking change assessment

Generated output changes (new interface, named-interface ctor signature, dual export, union parameter type + normalization). The consumer-facing contract is backward compatible: object literals still satisfy the named interface, the class is still exported under the same name, and the union only widens what channels accept. Shipping as feat:.

Testing

  • Unit: 53 suites / 651 tests green; only parameters + channels snapshots changed.
  • Blackbox: 12/12 type-check pass.
  • Runtime (live brokers/servers): NATS, Kafka, MQTT, AMQP, WebSocket, EventSource, HTTP all pass, incl. a new plain-object ≡ class-instance parity test.
  • Full regeneration reproduces the committed runtime tree with zero diffs.
  • Docs (docs/generators/parameters.md) + example (examples/openapi-http-client) updated and regenerated.

Notes

  • Removed three dead realize* helpers from generators/typescript/utils.ts.
  • prepare:pr's final npm ci step fails locally on a pre-existing test/runtime/typescript lockfile drift (missing @swc/core platform binaries) — untouched by this PR; all substantive steps (build, generate:assets, lint:fix, test:update, regeneration) pass.

🤖 Generated with Claude Code

jonaslagoni and others added 10 commits July 14, 2026 21:42
Add buildParametersInterfaceBody + export/fix realizeParameterForChannelWithType
in generators/typescript/utils.ts; add parameterUnionType +
renderParameterNormalization emitters in channels/utils.ts, with unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add self (prepend companion interface) and ctor (rewrite signature to
input: <Name>Interface) hooks to the OpenAPI parameter class preset; rewrite
the trailing export to include <Name>Interface in the parameters Core loop.
buildParametersInterfaceBody now skips const properties to match the ctor
input type. Regenerated OpenAPI parameter surfaces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract parameterClassPreset factory (self + ctor + additionalContent) into
generators/typescript/utils.ts and use it from both the OpenAPI and AsyncAPI
parameter generators so the interface/ctor logic stays in one place.
Regenerated AsyncAPI parameter surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
addParametersToDependencies now emits a single named import bringing in both
<Name> and <Name>Interface for every protocol channel consumer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The operation context parameters field now accepts <Name>Interface | <Name>,
and the function body normalizes context.parameters to a class instance before
buildUrlWithParameters. Regenerated path-organization http_client surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every user-input parameter site in NATS, Kafka, MQTT, AMQP, EventSource and
WebSocket now accepts <Name>Interface | <Name> and normalizes to a class
instance before use — inline at the single topic/subject build site (via
parameterInstanceExpression) for broker publishers/subscribers, and via a
parameterInstance local for WebSocket (which passes it to callbacks).
Callback params and createFromChannel-built instances stay class-typed.
Regenerated runtime channel surfaces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Snapshots reflect the companion interface + rewritten ctor + dual export on
parameter models, and the Interface | Class union + instanceof normalization +
dual import on channel consumers. No unrelated generator snapshots changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a Companion Interface section to the parameters generator docs, show the
plain-object ergonomic in the openapi-http-client example (README + demo), and
regenerate the example output with the interface/union.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an HTTP client test asserting a plain object satisfying the parameter
interface resolves to the identical path as a class instance. Verified the
regenerated channel code semantically across NATS, Kafka, MQTT, AMQP,
WebSocket, EventSource and HTTP against live brokers/servers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Preset self/ctor logic is shared via parameterClassPreset, and every channel
consumer uses the shared union/normalization emitters (no inline duplication).
Remove the unused realizeParametersForChannel, realizeParameterForChannelWithType,
and realizeParametersForChannelWithoutType helpers (and their tests) rather than
retain dead code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jonaslagoni
jonaslagoni requested a review from ALagoni97 as a code owner July 14, 2026 20:28
@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
the-codegen-project Ready Ready Preview, Comment Jul 15, 2026 6:05pm
the-codegen-project-mcp Ready Ready Preview, Comment Jul 15, 2026 6:05pm

# Conflicts:
#	src/codegen/generators/typescript/channels/protocols/http/client.ts
#	test/codegen/generators/typescript/__snapshots__/channels.spec.ts.snap
#	test/runtime/typescript/src/request-reply/channels/http_client.ts
@ALagoni97

Copy link
Copy Markdown
Contributor

Even though i like that we change to get the interface approach, i still don't see the value in the class based parameters / headers / payloads. 🤔

Resolve conflicts in the TypeScript HTTP client generator: combine the
parameter-interface normalization (this branch) with main's typed-header
handling and baseUrl-based URL building. Extract generateHeadersInit to keep
generateFunctionImplementation under the cognitive-complexity limit. Snapshot
regenerated via jest -u.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nerator

The parity test still passed the pre-merge `server` config key; main renamed it
to `baseUrl`, so the URL was ignored and fetch hit the default host. Switch it to
`baseUrl` and regenerate the committed runtime src so it matches the merged
generator output (baseUrl-based URLs, typed-header serialization, parameter
normalization).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jonaslagoni

Copy link
Copy Markdown
Contributor Author

🎉 This PR is included in version 0.76.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants