feat(transformers): support Temporal API for date types#3916
Conversation
|
|
|
@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 detectedLatest commit: bfa457a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
There was a problem hiding this comment.
Note
Mergeable as-is. One follow-up worth doing: the user-facing docs page at web/src/content/docs/docs/openapi/typescript/plugins/transformers.mdx — Dates 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
datesconfig toboolean | 'date' | 'temporal'—'temporal'opts into Temporal types andTemporal.X.from(value)transformers;'date'is an explicit alias for the existingDatedefault. - Add
temporalExpressionsExpressionTransformer — mirrorsdateExpressionsbut emitsTemporal.Instant.from(...)/Temporal.PlainDate.from(...)and registers theTemporalsymbol viaplugin.symbolOncefromtemporal-polyfill. - Emit Temporal type nodes in the TypeScript plugin —
string.tsreturnsTemporal.PlainDate/Temporal.Instantwhentransformers.config.dates === 'temporal', falling through toDateotherwise. - New snapshot spec & coverage —
specs/3.1.x/transformers-temporal.jsonplus a full snapshot suite undertransformers-temporal/exercising scalardate-time, scalardate, and an array ofdate-time.
Summary | 23 files | 1 commit | base: main ← feat/transformers-temporal
dates becomes a tri-state
Before:
dates?: boolean— onlyDateor off.
After:dates?: boolean | 'date' | 'temporal'—true/'date'keepDate,'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.
temporalExpressions mirrors dateExpressions
Before: Only
new Date(value)was emitted forstring/date(-time)runtime transforms.
After: Whendates === 'temporal', the generated transformer callsTemporal.Instant.from(value)fordate-timeandTemporal.PlainDate.from(value)fordate.
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.
Snapshot coverage
Before: No fixture exercised Temporal output.
After:specs/3.1.x/transformers-temporal.jsoncovers scalardate-time, scalardate, andarray<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.
Claude Opus | 𝕏
494e35e to
02cd504
Compare
02cd504 to
bfa457a
Compare
Codecov Report❌ Patch coverage is 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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
The CI builds seem flaky, probably just needs a re-run |

Closes #1883.
Adds
dates: 'temporal'to@hey-api/transformers. With it set:string/date-timebecomesTemporal.Instant,string/datebecomesTemporal.PlainDateTemporal.X.from(value)Temporalis imported fromtemporal-polyfilldates: truekeeps the existingDatebehavior. The type widens frombooleantoboolean | 'date' | 'temporal'.Test plan
pnpm typecheckpnpm vitest run --project @hey-api/openapi-tspnpm vitest run --project @test/openapi-ts(new snapshot undertransformers-temporal)