Skip to content

feat(transformers): support Temporal API for date types#3916

Open
OptoCloud wants to merge 1 commit into
hey-api:mainfrom
OptoCloud:feat/transformers-temporal
Open

feat(transformers): support Temporal API for date types#3916
OptoCloud wants to merge 1 commit into
hey-api:mainfrom
OptoCloud:feat/transformers-temporal

Conversation

@OptoCloud
Copy link
Copy Markdown

Closes #1883.

Adds dates: 'temporal' to @hey-api/transformers. With it set:

  • string/date-time becomes Temporal.Instant, string/date becomes Temporal.PlainDate
  • response transformers call Temporal.X.from(value)
  • Temporal is imported from temporal-polyfill

dates: true keeps the existing Date behavior. The type widens from boolean to boolean | 'date' | 'temporal'.

Test plan

  • pnpm typecheck
  • pnpm vitest run --project @hey-api/openapi-ts
  • pnpm vitest run --project @test/openapi-ts (new snapshot under transformers-temporal)

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

@OptoCloud is attempting to deploy a commit to the Hey API Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 19, 2026

🦋 Changeset detected

Latest commit: bfa457a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hey-api/openapi-ts Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. feature 🚀 Feature request. labels May 19, 2026
Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Mergeable as-is. One follow-up worth doing: the user-facing docs page at web/src/content/docs/docs/openapi/typescript/plugins/transformers.mdxDates section — still describes dates: true as the only option and doesn't mention 'temporal'. The JSDoc on the config type is updated, but the website page is the primary discovery surface for this option. Not a blocker; consider a follow-up doc patch.

TL;DR — Adds a dates: 'temporal' option to @hey-api/transformers so generated types and response transformers can use the Temporal API (Temporal.Instant for date-time, Temporal.PlainDate for date) imported from temporal-polyfill, while dates: true keeps the existing Date behavior. Closes #1883.

Key changes

  • Widen dates config to boolean | 'date' | 'temporal''temporal' opts into Temporal types and Temporal.X.from(value) transformers; 'date' is an explicit alias for the existing Date default.
  • Add temporalExpressions ExpressionTransformer — mirrors dateExpressions but emits Temporal.Instant.from(...) / Temporal.PlainDate.from(...) and registers the Temporal symbol via plugin.symbolOnce from temporal-polyfill.
  • Emit Temporal type nodes in the TypeScript pluginstring.ts returns Temporal.PlainDate / Temporal.Instant when transformers.config.dates === 'temporal', falling through to Date otherwise.
  • New snapshot spec & coveragespecs/3.1.x/transformers-temporal.json plus a full snapshot suite under transformers-temporal/ exercising scalar date-time, scalar date, and an array of date-time.

Summary | 23 files | 1 commit | base: mainfeat/transformers-temporal


dates becomes a tri-state

Before: dates?: boolean — only Date or off.
After: dates?: boolean | 'date' | 'temporal'true/'date' keep Date, 'temporal' switches the emitted types and response transformers to Temporal.

The widening is backward-compatible: existing dates: true (and the default in defaultConfig) keep the existing behavior. resolveConfig selects temporalExpressions only when dates === 'temporal', otherwise falls through to dateExpressions for any other truthy value — so 'date' works as a documented alias without an additional branch.

config.ts · types.ts


temporalExpressions mirrors dateExpressions

Before: Only new Date(value) was emitted for string/date(-time) runtime transforms.
After: When dates === 'temporal', the generated transformer calls Temporal.Instant.from(value) for date-time and Temporal.PlainDate.from(value) for date.

The new transformer follows the same dataExpression-shape branching as dateExpressions (string → return Temporal.X.from(s); expression → in-place assign), and reuses the symbol system via plugin.symbolOnce('Temporal', { external: 'temporal-polyfill' }) so the import is hoisted once. Note: Temporal.Instant.from is stricter than new Date — it requires the input to be an exact-instant string (RFC 3339-compliant date-time with offset). For OpenAPI-compliant inputs this is fine; servers emitting offset-less date-time would have been silently accepted by Date and will now throw at parse time. That's an improvement in correctness, not a regression, but worth being aware of.

expressions.ts · string.ts


Snapshot coverage

Before: No fixture exercised Temporal output.
After: specs/3.1.x/transformers-temporal.json covers scalar date-time, scalar date, and array<date-time>, with a full generated-output snapshot under __snapshots__/3.1.x/transformers-temporal/.

The snapshot validates both the type emission (Temporal.Instant, Temporal.PlainDate, Array<Temporal.Instant>) and the array-iteration path in the transformer (data.events.map((item: any) => Temporal.Instant.from(item))), which is the trickiest of the three shapes.

transformers-temporal.json

Pullfrog  | View workflow run | Using Claude Opus𝕏

@OptoCloud OptoCloud force-pushed the feat/transformers-temporal branch from 494e35e to 02cd504 Compare May 19, 2026 15:59
@OptoCloud OptoCloud force-pushed the feat/transformers-temporal branch from 02cd504 to bfa457a Compare May 19, 2026 16:01
@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

❌ Patch coverage is 5.88235% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.68%. Comparing base (0c865e1) to head (bfa457a).

Files with missing lines Patch % Lines
...s/src/plugins/@hey-api/transformers/expressions.ts 10.00% 5 Missing and 4 partials ⚠️
...src/plugins/@hey-api/typescript/v1/toAst/string.ts 0.00% 2 Missing and 3 partials ⚠️
...api-ts/src/plugins/@hey-api/transformers/config.ts 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3916      +/-   ##
==========================================
- Coverage   37.70%   37.68%   -0.03%     
==========================================
  Files         582      582              
  Lines       20844    20859      +15     
  Branches     6063     6070       +7     
==========================================
+ Hits         7860     7861       +1     
- Misses      10570    10577       +7     
- Partials     2414     2421       +7     
Flag Coverage Δ
unittests 37.68% <5.88%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@OptoCloud
Copy link
Copy Markdown
Author

The CI builds seem flaky, probably just needs a re-run

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

Labels

feature 🚀 Feature request. size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Customizing Generated Date Types to Use Temporal.Instant

1 participant