Skip to content

fix: generate tsc-safe TypeScript for parameters and payloads presets#374

Closed
ALagoni97 wants to merge 1 commit into
mainfrom
fix/openapi-ts-parameters-payloads-tsc
Closed

fix: generate tsc-safe TypeScript for parameters and payloads presets#374
ALagoni97 wants to merge 1 commit into
mainfrom
fix/openapi-ts-parameters-payloads-tsc

Conversation

@ALagoni97

@ALagoni97 ALagoni97 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Note for reviewers: the payloads/headers fix (#373, defects 3 & 4) is implemented here as a post-processing preset because @asyncapi/modelina@6.0.0-next.11 is an external published package with no patch tooling in this repo. These two defects could alternatively be solved upstream in Modelina's MarshalFunction/UnmarshalFunction (lib/.../generators/typescript/presets/utils/) instead — that would be a separate repo and release. The preset keeps the fix self-contained and testable here.

Problem

Generation reports zero errors, but the generated .ts does not compile. A downstream publish pipeline runs npm i && npm run build && npm publish; the tsc build step exits non-zero and nothing publishes. These are silent-at-generation, fatal-at-build defects.

Fixes four independent template defects across two presets, tracked upstream as #372 (parameters) and #373 (payloads).

Defects & fixes

parameters preset — #372 (src/codegen/inputs/openapi/generators/parameters.ts)

  1. Query serializer/deserializer used the raw spec name as the property accessor. Fields are constrained to camelCase (skip) but the code emitted this.SkipTS2551 Property 'Skip' does not exist. Introduced a ParameterConfig carrying both name (original wire key) and propertyName (constrained accessor), plus a buildConstrainedNameMap() helper. Every this.* accessor now uses the constrained name; every wire key (params.append('Skip'), params.has(...), URL placeholders, extractPathParameters switch cases) keeps the original casing. The path serializer already behaved correctly; this makes serialize, deserialize, fromUrl, and extractPathParameters consistent.
  2. deserializeUrl was only generated when the class had query params, but fromUrl() always calls it. A path-only parameters class failed with TS2551 Property 'deserializeUrl' does not exist. deserializeUrl is now always emitted (a harmless no-op when there are no query params).

payloads / headers presets — #373 (new src/codegen/modelina/presets/marshalling.ts)

These defects originate in Modelina's TS_COMMON_PRESET marshalling. Modelina is an external published package with no patch tooling in this repo, so the fix is a small post-processing preset (createMarshallingFixPreset) that runs immediately after TS_COMMON_PRESET. Each replacement is derived from the model, so it targets exactly the affected property line and leaves everything else untouched.

  1. Unconditional null fallback for non-nullable date-time in unmarshal(). instance.created = obj["created"] == null ? null : new Date(...) yields Date | null where the field is declared DateTS2322. The null branch is dropped for required, non-nullable date fields.
  2. Nullable array guarded only by !== undefined in marshal(), then iterated. null slips past the guard into for (const item of this.signers)TS2531 Object is possibly 'null'. An explicit !== null guard is added.

Wired into both payloads.ts and headers.ts, which share the same marshalling setup.

Verification

Closes #372
Closes #373

🤖 Generated with Claude Code

Generation reported zero errors but the emitted .ts failed `tsc`, breaking
downstream `npm run build` in publish pipelines. Four template defects across
two presets are fixed.

parameters preset (#372):
- Serialize/deserialize now access the constrained camelCase field
  (this.skip) instead of the raw spec name (this.Skip), while the wire key
  (params.append('Skip'), path placeholders, extractPathParameters cases)
  keeps the original casing. Threaded a ParameterConfig carrying both names.
- Always emit deserializeUrl (a no-op with no query params) so path-only
  classes, whose fromUrl() calls it unconditionally, compile.

payloads/headers presets (#373):
- New createMarshallingFixPreset corrects Modelina's class marshal/unmarshal
  output (Modelina is an external package with no patch tooling). Derived
  from the model so each replacement targets only the affected property:
  - drop the `== null ? null : new Date(...)` fallback for required,
    non-nullable date-time fields (was Date | null, declared Date).
  - null-guard nullable arrays before iterating them in marshal().

Verified by regenerating both minimal repros and the full safepay-v2 client
through tsc --strict (clean), plus regression tests for all four defects.

Refs: #372, #373

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ALagoni97 ALagoni97 requested a review from jonaslagoni as a code owner July 2, 2026 18:42
@netlify

netlify Bot commented Jul 2, 2026

Copy link
Copy Markdown

Deploy Preview for the-codegen-project canceled.

Name Link
🔨 Latest commit a6558e7
🔍 Latest deploy log https://app.netlify.com/projects/the-codegen-project/deploys/6a46b10498687a0008253073

@vercel

vercel Bot commented Jul 2, 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 2, 2026 6:46pm
the-codegen-project-mcp Ready Ready Preview, Comment Jul 2, 2026 6:46pm

@jonaslagoni

Copy link
Copy Markdown
Contributor

I am gonna fix it upstream as this is just a temporary hotfix, give me a day or so

@jonaslagoni jonaslagoni closed this Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants