ReviewOS

zig-utils/zig-js

Errors: Intl option errors should enumerate the legal values as JavaScriptCore does

#901
Closed chris opened this 11 days ago ·
11 days ago

Parent: #459

Problem

When an Intl option gets an out-of-range value, JavaScriptCore enumerates the legal values. zig-js emits a generic template with no list — and does so via two different templates, one of which drops the offending value entirely. A differential over the Intl surface found 19 cases from this single helper.

sourcezig-jsJavaScriptCore
new Intl.DateTimeFormat('en', {hour:'bogus'})invalid value 'bogus' for option hourhour must be "2-digit" or "numeric"
new Intl.DateTimeFormat('en', {dateStyle:'bogus'})invalid value 'bogus' for option dateStyledateStyle must be "full", "long", "medium", or "short"
new Intl.NumberFormat('en', {style:'bogus'})invalid value for option stylestyle must be either "decimal", "percent", "currency", or "unit"
new Intl.PluralRules('en', {type:'bogus'})invalid value for option typetype must be "cardinal" or "ordinal"

Details that matter for exact parity

  • Values are double-quoted, with an Oxford comma before the final or.
  • JSC includes the word "either" for some options and not others, and it does not correlate with the number of choices. Observed WITH "either": formatMatcher, localeMatcher, usage, numeric, fallback, style. Observed WITHOUT: hour, dateStyle, type. This has to be per-option data, not a rule derived from the value count.
  • zig-js is internally inconsistent today and should be unified first regardless of wording: 13 cases use invalid value '<v>' for option <name> and 6 use invalid value for option <name>, silently dropping the value the user passed (style, notation, currencyDisplay, roundingMode, localeMatcher, and PluralRules type).

Suggested shape

The option-reading helper already knows the allowed set — it validates against it. Have it render the list, and carry a per-option "either" flag. One helper, one fix.

Verification

scratchpad/sweep/probe.sh diffs zig-js against a real JavaScriptCore backend. Drive probes from inside a function: zig-js --eval runs script code, so an indirect eval shares global scope with the harness and a case declaring var i truncates the run.

11 days ago

Landed in 383d3fe. A 63-case differential goes 5/63 → 60/63.

The issue's framing — "one shared helper, so this is ONE fix" — was right about the mechanism and wrong about the difficulty. Three things turned out to be per-option data rather than rules that could be derived, and each one produced a wrong message until it was measured:

1. "either" does not follow the value count, nor the constructor. The issue guessed it correlated with a two-way choice. It does not:

omits "either"includes "either"
DateTimeFormat components (weekday, era, month, day, hour, …)DateTimeFormat's own localeMatcher, formatMatcher
Intl.PluralRules typeIntl.ListFormat type, Intl.DisplayNames type

2. The value ORDER is per-option. style is long-first for Intl.RelativeTimeFormat and Intl.ListFormat but narrow-first for Intl.DisplayNames. Reordering by matching the array literal silently broke the first two; only re-running the differential caught it.

3. useGrouping cannot use the generic renderer — it mixes booleans with strings and JSC leaves the booleans unquoted: useGrouping must be either true, false, "min2", "auto", or "always".

Also landed, all measured

Well-formedness wording for calendar, numberingSystem, collation, currency and unit; <name> is out of range (was <name> value is out of range); and the DisplayNames missing-type message.

A regression I introduced and caught

JSC names the offending tag from CanonicalizeLocaleList but not from the Intl.Locale constructor:

new Intl.NumberFormat('!!bogus!!')  ->  invalid language tag: !!bogus!!
new Intl.Locale('!!bogus!!')        ->  invalid language tag

Both paths share one helper in zig-js, and collapsing them to the bare form broke the first. Split at that helper; both forms are pinned by the new test.

Three deliberate remaining differences

All are places zig-js is the more accurate:

  • currencyDisplay accepts narrowSymbol (spec since ES2020) and lists it; JSC's message omits it. Matching would print a list contradicting what zig-js accepts.
  • Intl.DurationFormat reports the real option name (years, yearsDisplay) where JSC reports style and display name, and lists numeric where JSC drops it.

--diag: 3,358 pass / 0 fail across intl402 3,341, String/prototype/localeCompare 13, Date/prototype/toLocaleString 4.

Sign in to comment on this issue.