diff --git a/core/engine/src/builtins/date/utils.rs b/core/engine/src/builtins/date/utils.rs index 964c63e541f..400ff1065c1 100644 --- a/core/engine/src/builtins/date/utils.rs +++ b/core/engine/src/builtins/date/utils.rs @@ -442,6 +442,14 @@ pub(super) fn make_date(day: f64, time: f64) -> f64 { tv } +#[cfg(feature = "intl")] +pub(crate) fn timestamp_for_first_of_month_utc(year: i32, month: u8) -> f64 { + debug_assert!((1..=12).contains(&month)); + let day = make_day(f64::from(year), f64::from(month - 1), 1.0); + let time = make_time(0.0, 0.0, 0.0, 0.0); + time_clip(make_date(day, time)) +} + /// Abstract operation `MakeFullYear ( year )` /// /// More info: diff --git a/core/engine/src/builtins/temporal/plain_year_month/mod.rs b/core/engine/src/builtins/temporal/plain_year_month/mod.rs index 1c328da5997..336245d8c4e 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -33,6 +33,10 @@ use super::{ to_temporal_duration, }; +#[cfg(feature = "temporal")] +#[cfg(test)] +mod tests; + /// The `Temporal.PlainYearMonth` built-in implementation /// /// More information: @@ -755,12 +759,15 @@ impl PlainYearMonth { /// /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plainyearmonth.tolocalestring /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toLocaleString + #[allow( + unused_variables, + reason = "`args` and `context` are used when the `intl` feature is enabled" + )] pub(crate) fn to_locale_string( this: &JsValue, - _: &[JsValue], - _: &mut Context, + args: &[JsValue], + context: &mut Context, ) -> JsResult { - // TODO: Update for ECMA-402 compliance let object = this.as_object(); let year_month = object .as_ref() @@ -769,7 +776,30 @@ impl PlainYearMonth { JsNativeError::typ().with_message("this value must be a PlainYearMonth object.") })?; - Ok(JsString::from(year_month.inner.to_string()).into()) + #[cfg(feature = "intl")] + { + use crate::builtins::{ + date::utils::timestamp_for_first_of_month_utc, + intl::date_time_format::{FormatDefaults, FormatType, format_date_time_locale}, + }; + let locales = args.get_or_undefined(0); + let options = args.get_or_undefined(1); + let timestamp = + timestamp_for_first_of_month_utc(year_month.inner.year(), year_month.inner.month()); + format_date_time_locale( + locales, + options, + FormatType::Date, + FormatDefaults::Date, + timestamp, + context, + ) + } + + #[cfg(not(feature = "intl"))] + { + Ok(JsString::from(year_month.inner.to_string()).into()) + } } /// 9.3.21 `Temporal.PlainYearMonth.prototype.toJSON ( )` diff --git a/core/engine/src/builtins/temporal/plain_year_month/tests.rs b/core/engine/src/builtins/temporal/plain_year_month/tests.rs new file mode 100644 index 00000000000..9d87b328a50 --- /dev/null +++ b/core/engine/src/builtins/temporal/plain_year_month/tests.rs @@ -0,0 +1,42 @@ +use crate::{JsNativeErrorKind, TestAction, run_test_actions}; + +#[test] +fn to_locale_string_returns_string() { + run_test_actions([ + TestAction::assert( + "typeof Temporal.PlainYearMonth.from('2024-03').toLocaleString() === 'string'", + ), + TestAction::assert("Temporal.PlainYearMonth.from('2024-03').toLocaleString().length > 0"), + ]); +} + +#[test] +fn to_locale_string_invalid_receiver_throws() { + run_test_actions([TestAction::assert_native_error( + "Temporal.PlainYearMonth.prototype.toLocaleString.call({})", + JsNativeErrorKind::Type, + "this value must be a PlainYearMonth object.", + )]); +} + +#[cfg(feature = "intl")] +#[test] +fn to_locale_string_different_locales_produce_different_output() { + run_test_actions([TestAction::assert( + "Temporal.PlainYearMonth.from('2024-03').toLocaleString('en-US') !== \ + Temporal.PlainYearMonth.from('2024-03').toLocaleString('de-DE')", + )]); +} + +#[cfg(feature = "intl")] +#[test] +fn to_locale_string_options_affect_output() { + run_test_actions([ + TestAction::assert( + "typeof Temporal.PlainYearMonth.from('2024-03').toLocaleString('en-US', { dateStyle: 'short' }) === 'string'", + ), + TestAction::assert( + "Temporal.PlainYearMonth.from('2024-03').toLocaleString('en-US', { dateStyle: 'short' }).length > 0", + ), + ]); +}