From 0a4bf6debed2d96bf3b43241648348081e2ceaa4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 19 Sep 2026 13:17:24 +0000 Subject: [PATCH] docs(core): say what formatMeasureDate's `Date.parse` guard actually rejects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `formatMeasureDate`'s inline note and the `ISO_DATETIME_RE` docblock both declared that a well-shaped impossible calendar date such as `2026-02-30` is unparseable and therefore "keeps falling through to `String(v)`, exactly as it does today". Measurement says the opposite, on BOTH arms: ECMAScript's Date Time String Format accepts `DD` in `01`-`31` syntactically and `MakeDay` rolls the surplus into the next month, so `Date.parse('2026-02-30')` returns an instant, not `NaN`, and the value renders as `2026-03-02`. What the guard actually rejects is an out-of-range MONTH (`2026-13-01`), which both patterns admit. Comment-only. No behaviour changes, no guard is added, and the pin that holds the rolled render in place is untouched and still green. The new prose cites that pin by its test name rather than restating its conclusion — a comment restating a pin is how the old paragraph came to assert a behaviour that nothing implemented — and points at the card carrying the open question of whether the shared display path should refuse an impossible calendar day at all. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_018HrVaotisyhgmot9o2MLRq --- ...taset-format-8263-impossible-date-prose.md | 17 ++++++++++ packages/core/src/utils/dataset-format.ts | 34 +++++++++++++++---- 2 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 .changeset/dataset-format-8263-impossible-date-prose.md diff --git a/.changeset/dataset-format-8263-impossible-date-prose.md b/.changeset/dataset-format-8263-impossible-date-prose.md new file mode 100644 index 0000000000..42a8135496 --- /dev/null +++ b/.changeset/dataset-format-8263-impossible-date-prose.md @@ -0,0 +1,17 @@ +--- +--- + +Comment-only repair in `@object-ui/core`'s `dataset-format.ts` — **no behaviour change**, so +nothing to release. + +`formatMeasureDate`'s inline note and the `ISO_DATETIME_RE` docblock both asserted that a +well-shaped impossible calendar date such as `2026-02-30` is unparseable and therefore "keeps +falling through to `String(v)`". Measurement on objectui#8263 showed the opposite on **both** +arms: ECMAScript's Date Time String Format accepts `DD` in `01`-`31` syntactically and `MakeDay` +rolls the surplus into the next month, so `Date.parse` returns an instant, not `NaN`. What the +guard actually rejects is an out-of-range **month** (`2026-13-01`), which the two patterns admit. + +Both sentences now say that. The rolled render itself is untouched and stays pinned by +`agrees with the list cell on a rolled-over date instead of second-guessing it` in the co-located +date suite, which the new prose points at rather than restates. Whether the shared display path +should refuse an impossible calendar day at all is carried by objectui#10026. diff --git a/packages/core/src/utils/dataset-format.ts b/packages/core/src/utils/dataset-format.ts index b7a022bbc9..a73b305369 100644 --- a/packages/core/src/utils/dataset-format.ts +++ b/packages/core/src/utils/dataset-format.ts @@ -148,8 +148,15 @@ const ISO_DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/; /** * ISO date carrying a time part — `2026-07-04T07:00:00.000Z`, or the same with * a space separator, with or without seconds/offset. Matched only as far as - * `HH:mm`; `Date.parse` decides the rest, so a well-shaped impossible instant - * still falls through untouched. + * `HH:mm`; `Date.parse` decides the rest. What it rejects is an out-of-range + * MONTH or CLOCK reading (`2026-13-01T09:30`, `2024-07-04T99:99`), which this + * pattern admits — such a value falls through untouched. + * + * ⛔ A DAY that overflows its month does NOT fall through. `2026-02-30T09:30` + * parses and renders rolled over, exactly as the date-only arm renders + * `2026-02-30`. See the note inside {@link formatMeasureDate} for the + * instrument that holds that render in place, and for where the open question + * about it lives. */ const ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}/; @@ -221,10 +228,25 @@ const ISO_DATETIME_RE = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}/; */ function formatMeasureDate(v: unknown, format: string | undefined, locale: string | undefined): string | undefined { if (typeof v !== 'string') return undefined; - // `Date.parse` guards both arms so a well-shaped impossible date - // (`2026-02-30`) is NOT swallowed into the em dash `formatDate` returns for - // an unparseable value — it keeps falling through to `String(v)`, exactly as - // it does today. Only a value that is genuinely a date changes. + // `Date.parse` guards both arms, and what it rejects is an out-of-range + // MONTH (`2026-13-01`) — which both patterns above admit — ⛔ NOT an + // out-of-range DAY. ECMAScript's Date Time String Format accepts `DD` in + // `01`-`31` syntactically and `MakeDay` rolls the surplus into the next + // month, so a well-shaped impossible date (`2026-02-30`) is PARSEABLE on + // both arms: it does not fall through to `String(v)`, it renders as the + // rolled-over day (`2026-03-02`). This paragraph asserted the opposite — + // that such a value keeps falling through — until objectui#8263 measured it. + // + // ⭐ That rolled render is not a leak in this guard; it is pinned, by + // `agrees with the list cell on a rolled-over date instead of second-guessing it` + // in this file's co-located date suite. Read that test for the argument. It + // is deliberately NOT restated here: a comment restating a pin is how this + // paragraph came to assert a behaviour that nothing implemented. + // + // ⚠️ Whether the SHARED display path should refuse an impossible calendar + // day at all is OPEN, and it is not this function's to answer alone — the + // authoring boundary already refuses such a value while the display path + // rolls it. objectui#10026 carries that question. if (ISO_DATE_ONLY_RE.test(v)) { return Number.isNaN(Date.parse(v)) ? undefined : formatDate(v, format, { locale }); }