feat(intl): implement Date.prototype.toLocaleString, toLocaleDateStri…#5080
feat(intl): implement Date.prototype.toLocaleString, toLocaleDateStri…#5080alienx5499 wants to merge 3 commits intoboa-dev:mainfrom
Conversation
…ng, and toLocaleTimeString
Test262 conformance changes
Fixed tests (6):Tested main commit: |
| let options = coerce_options_to_object(options, context)?; | ||
| if format_type != FormatType::Time | ||
| && get_option::<DateStyle>(&options, js_string!("dateStyle"), context)?.is_none() | ||
| { | ||
| options.create_data_property_or_throw( | ||
| js_string!("dateStyle"), | ||
| JsValue::from(js_string!("long")), | ||
| context, | ||
| )?; | ||
| } | ||
| if format_type != FormatType::Date | ||
| && get_option::<TimeStyle>(&options, js_string!("timeStyle"), context)?.is_none() | ||
| { | ||
| options.create_data_property_or_throw( | ||
| js_string!("timeStyle"), | ||
| JsValue::from(js_string!("long")), | ||
| context, | ||
| )?; | ||
| } | ||
| let new_target = context | ||
| .intrinsics() | ||
| .constructors() | ||
| .date_time_format() | ||
| .constructor() | ||
| .into(); | ||
| let options_value = options.into(); | ||
| let dtf = create_date_time_format( | ||
| &new_target, | ||
| locales, | ||
| &options_value, | ||
| format_type, | ||
| defaults, | ||
| context, | ||
| )?; | ||
| let format_val = dtf.get(js_string!("format"), context)?; | ||
| let format_fn = format_val | ||
| .as_callable() | ||
| .ok_or_else(|| JsNativeError::typ().with_message("format is not callable"))?; | ||
| format_fn.call(&dtf.into(), &[JsValue::from(timestamp)], context) | ||
| } |
There was a problem hiding this comment.
I don't think this is the correct approach. This is interacting with DateTimeFormat as if it was an external crate to be consumed, but since the creation of the formatter is not visible to the external world, we can get away with calling create_date_time_format directly.
My suggestion here would be to tweak create_date_time_format such that it returns DateTimeFormatter directly, then use that here to avoid creating a new JsObject, and move the object creation logic to the constructor instead
There was a problem hiding this comment.
Kinda weird to do it this way in here but use the correct approach in Number.prototype.toLocaleString by the way
There was a problem hiding this comment.
Thanks for the suggestion! I refactored create_date_time_format to return the internal DateTimeFormat and moved the JsObject creation into the constructor. Date.prototype.toLocaleString and related methods now format directly using the internal formatter, similar to Number.prototype.toLocaleString. Addressed in 725441e.
…void JS alloc in Date toLocaleString path
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5080 +/- ##
===========================================
+ Coverage 47.24% 59.02% +11.78%
===========================================
Files 476 563 +87
Lines 46892 62725 +15833
===========================================
+ Hits 22154 37026 +14872
- Misses 24738 25699 +961 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
nekevss
left a comment
There was a problem hiding this comment.
Noticed a couple things while reviewing this.
core/engine/src/builtins/date/mod.rs
Outdated
| func.call(this, &[], context) | ||
| } | ||
|
|
||
| /// Returns the `[[DateValue]]` internal slot (RequireInternalSlot(dateObject, `[[DateValue]]`)). |
There was a problem hiding this comment.
nit: accessing the inner field should remain as the current style.
core/engine/src/builtins/date/mod.rs
Outdated
| // Let dateObject be the this value. | ||
| // Perform ? RequireInternalSlot(dateObject, [[DateValue]]). | ||
| // Let x be dateObject.[[DateValue]]. | ||
| let t = Self::this_date_value(this)?; |
There was a problem hiding this comment.
issue: these steps are only applicable to the intl flagged implementation.
core/engine/src/builtins/date/mod.rs
Outdated
| Err(JsError::from_opaque(JsValue::new(js_string!( | ||
| "Function Unimplemented]" | ||
| )))) | ||
| // Let dateObject be the this value. |
There was a problem hiding this comment.
nit: style, include the step numbers alongside the spec steps
| let needs_defaults = format_options.check_dtf_type(date_time_format_type); | ||
| // d. If needDefaults is true and defaults is either date or all, then | ||
| if needs_defaults && defaults != FormatDefaults::Time { | ||
| if needs_defaults && (defaults == FormatDefaults::All || defaults == FormatDefaults::Date) { |
There was a problem hiding this comment.
question: why was this changed? The previous looks correct and acts in less steps
| context: &mut Context, | ||
| ) -> JsResult<JsString> { | ||
| // FormatDateTime / PartitionDateTimePattern: TimeClip, then ToLocalTime, then format. | ||
| let x = time_clip(timestamp); |
There was a problem hiding this comment.
issue: we should not be handling this logic again.
We already handle this logic in two different places. There should not be a reason to implement it a second time. Maybe you're looking for ToLocalTime?
fa1bd92 to
755481e
Compare
|
Hi @nekevss, I've pushed updates addressing the review comments and resolved the outdated threads. Could you please take another look when you have time? Thanks! |
This Pull Request fixes/closes #5075.
It changes the following:
Date.prototype.toLocaleString,toLocaleDateString, andtoLocaleTimeStringusingIntl.DateTimeFormatwhen theintlfeature is enabled (ECMA-402 20.4.1–20.4.3).format_date_time_localeinintl/date_time_format; exposecreate_date_time_formataspub(crate); addFormatDefaults::Alland fix default-application logic for it.this_date_valuehelper for the RequireInternalSlot /[[DateValue]]step in the three methods."Invalid Date"for NaN in all three methods; whenintlis disabled, fall back toDate.prototype.toString.#[cfg(feature = "intl")]tests: invalid receiver (TypeError), NaN →"Invalid Date",typeofchecks, locale differences (en-US vs de-DE) for all three methods, and options pipeline (dateStyle: 'short').Testing
cargo test -p boa_engine --lib -- date::tests::date_proto_to_locale_string_intl(without intl; test is skipped)cargo test -p boa_engine --features intl_bundled --lib -- date::tests::date_proto_to_locale_string_intl(with intl)