feat: Add temporal support#230
Draft
DecimalTurn wants to merge 23 commits into
Draft
Conversation
There was a problem hiding this comment.
Pull request overview
Adds opt-in support for parsing TOML date/time values into JavaScript Temporal objects, and extends stringify/patch logic to accept Temporal inputs while keeping existing Date-subclass behavior as the default for backward compatibility.
Changes:
- Introduces
ParseOptions.temporaland threads it throughparse()/TomlDocument/toJS()so TOML date/time nodes can return Temporal objects. - Adds Temporal duck-typing utilities plus Temporal-aware diffing/patching/stringification paths.
- Adds Temporal-focused documentation and a new Jest test suite (with polyfill).
Reviewed changes
Copilot reviewed 15 out of 17 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/utils.ts |
Adds Temporal detection + Temporal-aware equality/stable stringification helpers. |
src/toml-document.ts |
Stores and applies the new temporal parse option when producing JS objects. |
src/to-js.ts |
Threads temporal option and converts TOML custom Date subclasses into Temporal values when enabled. |
src/temporal-global.d.ts |
Adds a minimal Temporal typing shim (currently as a global declaration). |
src/patch.ts |
Auto-detects Temporal in updated, threads temporal mode through toJS, and preserves Temporal date/time serialization. |
src/parse-options.ts |
Documents and adds the new temporal?: boolean option. |
src/parse-js.ts |
Detects Temporal inputs during stringify and routes them through Temporal-aware CST generation. |
src/index.ts |
Documents and forwards options.temporal through parse(). |
src/generate.ts |
Adds generateTemporalDateTime() to serialize Temporal objects to TOML date/time nodes. |
src/__tests__/temporal.test.ts |
Adds Temporal integration tests using @js-temporal/polyfill. |
README.md |
Documents default Date-subclass behavior vs opt-in Temporal behavior + examples. |
package.json / pnpm-lock.yaml |
Adds @js-temporal/polyfill dev dependency for tests. |
CHANGELOG.md |
Notes Temporal support additions. |
PLAN-temporal.md |
Adds implementation plan/notes for Temporal support. |
.github/workflows/test-and-build.yml |
Expands CI Node matrix to include Node 26.x. |
.github/workflows/node-engine-check.yml |
Updates engine check job to Node 26. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
@js-temporal/polyfill does not provide getISOFields; only native Temporal implementations do. Keep the equals check which exists on both.
ZonedDateTime.toString() includes IANA annotations that TOML strips, causing spurious diffs. Use temporalToTomlString for consistency.
TOML only supports offset timezones. ZonedDateTime with IANA annotations now throws a clear error. Offset timezones are still accepted. Fixed dateValueToTemporal to use +00:00 instead of UTC.
temporalToTomlString always emits T, but the existing TOML may use a space separator. Re-apply the separator from existing.raw.
…ralDateTime Centralizes TOML validation (bracket rejection, Z normalization) through temporalToTomlString instead of raw toString().
Temporarily remove globalThis.Temporal to verify the runtime guard throws a clear error.
Comment on lines
+83
to
+85
| if (value instanceof LocalDateTime) { | ||
| return T.PlainDateTime.from(value.toISOString()); | ||
| } |
Comment on lines
+87
to
+98
| if (value instanceof OffsetDateTime) { | ||
| const iso = value.toISOString(); | ||
| // Extract offset: e.g. "2024-01-15T10:30:00+05:30" or "2024-01-15T10:30:00Z" | ||
| const offsetMatch = iso.match(/([+-]\d{2}:\d{2}|Z)$/); | ||
| const offset = offsetMatch ? offsetMatch[1] : 'Z'; | ||
| // Strip offset suffix to get the plain datetime | ||
| const plainIso = iso.replace(/([+-]\d{2}:\d{2}|Z)$/, ''); | ||
| // ZonedDateTime.from requires a timezone. Use the offset itself so the | ||
| // resulting object has an offset timezone (not IANA), which TOML can represent. | ||
| const tz = offset === 'Z' ? '+00:00' : offset; | ||
| return T.ZonedDateTime.from(`${plainIso}${offset}[${tz}]`); | ||
| } |
Comment on lines
+441
to
+444
| if (truncateZeroTimeInDates) { | ||
| const T = (globalThis as any).Temporal; | ||
| const plainDate = T.PlainDate.from(value.toString().split('T')[0]); | ||
| if (plainDate.toString() + 'T00:00:00' === value.toString().slice(0, 19)) { |
Comment on lines
+86
to
+88
| // Normalize +00:00 to Z | ||
| return full.replace(/\[.*\]$/, '').replace('+00:00', 'Z'); | ||
| } |
Comment on lines
+89
to
+91
|
|
||
| return value.toString(); | ||
| } |
Comment on lines
+59
to
+73
| stringify({ | ||
| start: Temporal.PlainDate.from('2024-01-15'), | ||
| due: Temporal.ZonedDateTime.from('2024-12-31T23:59:59Z[UTC]') | ||
| }); | ||
| // start = 2024-01-15 | ||
| // due = 2024-12-31T23:59:59Z | ||
|
|
||
| patch('d = 2024-01-15\n', { | ||
| d: Temporal.PlainDateTime.from('2025-06-01T12:00:00') | ||
| }); | ||
| // d = 2025-06-01T12:00:00 | ||
| ``` | ||
|
|
||
| > **Note:** TOML only supports timezone offsets (`+05:30`, `Z`), not IANA timezone names. When a `Temporal.ZonedDateTime` with an IANA annotation (e.g. `[Asia/Kolkata]`) is serialized, only the offset portion is kept. | ||
|
|
| ### Added | ||
|
|
||
| - Parsing: New `temporal` option in `ParseOptions`. When `true`, TOML date/time values are returned as [Temporal](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Temporal) objects (`Temporal.PlainDate`, `Temporal.PlainTime`, `Temporal.PlainDateTime`, `Temporal.ZonedDateTime`) instead of custom `Date` subclasses. | ||
| - Stringify: Auto-detect Temporal objects in the input JS and serialize them to the correct TOML date/time type. `ZonedDateTime` IANA annotations are stripped (TOML only supports offsets). |
Comment on lines
+16
to
+18
| * The Temporal API must be available in the runtime (it is Stage 4 | ||
| * and shipping in modern browsers and Node.js). | ||
| * |
| 1. **`temporal` is opt-in (default `false`).** This avoids a breaking change. In a future major version it could become opt-out or the default once Temporal reaches Baseline. | ||
| 2. **Temporal detection in serialize path is automatic.** If a user has a Temporal object in their JS, we want it to serialize correctly without extra configuration. | ||
| 3. **Duck-typing for Temporal detection** rather than `instanceof` checks, because Temporal objects may come from different realms (e.g., iframes, vm contexts). | ||
| 4. **For `ZonedDateTime` with IANA timezone**, we strip the IANA annotation and keep only the offset in TOML output. TOML does not support IANA timezone names. |
Comment on lines
+4
to
+7
| * Uses @js-temporal/polyfill because Node.js 24 does not yet ship | ||
| * Temporal natively (Stage 4 spec, expected in a future release). | ||
| * The polyfill is set on globalThis so the library code can access it | ||
| * the same way it would access the native Temporal global. |
LocalDateTime and OffsetDateTime toISOString() return a space separator when the original TOML used one. Temporal.from() requires T.
… on all Temporal types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces support for the (new) JavaScript Temporal API.
The implementation is opt-in via a new
temporaloption.Temporal API Integration:
temporal: booleanoption toParseOptions, allowing TOML date/time values to be parsed as Temporal objects when enabled.