From 1af44942a98de240469b355f3851f2ba24ff9c9c Mon Sep 17 00:00:00 2001 From: Albert Leigh Date: Fri, 27 Dec 2024 01:10:58 +0800 Subject: [PATCH 1/2] fix very minor typo shift -> unshift (#4097) --- core/engine/src/object/builtins/jsarray.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/engine/src/object/builtins/jsarray.rs b/core/engine/src/object/builtins/jsarray.rs index 27457869443..2e3e1462b1e 100644 --- a/core/engine/src/object/builtins/jsarray.rs +++ b/core/engine/src/object/builtins/jsarray.rs @@ -100,7 +100,7 @@ impl JsArray { /// Calls `Array.prototype.unshift()`. #[inline] pub fn unshift(&self, items: &[JsValue], context: &mut Context) -> JsResult { - Array::shift(&self.inner.clone().into(), items, context) + Array::unshift(&self.inner.clone().into(), items, context) } /// Calls `Array.prototype.reverse()`. From fdd8acc6a9c0010f4c11fb2839d08920f2789a80 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Fri, 27 Dec 2024 17:15:40 -0600 Subject: [PATCH 2/2] Bump the temporal_rs version and related changes (#4098) --- Cargo.lock | 2 +- Cargo.toml | 2 +- .../src/builtins/temporal/duration/mod.rs | 17 +-- .../src/builtins/temporal/instant/mod.rs | 4 +- core/engine/src/builtins/temporal/mod.rs | 124 +++++++++++------- core/engine/src/builtins/temporal/now.rs | 41 ++++-- .../src/builtins/temporal/plain_date/mod.rs | 63 ++++----- .../builtins/temporal/plain_date_time/mod.rs | 45 +++---- .../builtins/temporal/plain_month_day/mod.rs | 17 +-- .../src/builtins/temporal/plain_time/mod.rs | 19 +-- .../builtins/temporal/plain_year_month/mod.rs | 6 +- .../builtins/temporal/zoneddatetime/mod.rs | 65 ++++----- 12 files changed, 209 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5c566e5cc1..1eb370735bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3467,7 +3467,7 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "temporal_rs" version = "0.0.4" -source = "git+https://github.com/boa-dev/temporal.git?rev=4498edf4efa52f0cdec0bbed8bf49cae7e543e74#4498edf4efa52f0cdec0bbed8bf49cae7e543e74" +source = "git+https://github.com/boa-dev/temporal.git?rev=8b796edec18a2652af282735aab4a2d0512b9a1d#8b796edec18a2652af282735aab4a2d0512b9a1d" dependencies = [ "bitflags 2.6.0", "combine", diff --git a/Cargo.toml b/Cargo.toml index 0b8b5119508..eeb61606646 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,7 +112,7 @@ intrusive-collections = "0.9.7" cfg-if = "1.0.0" either = "1.13.0" sys-locale = "0.3.2" -temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "4498edf4efa52f0cdec0bbed8bf49cae7e543e74", features = ["tzdb", "now"] } +temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "8b796edec18a2652af282735aab4a2d0512b9a1d", features = ["tzdb", "now"] } web-time = "1.1.0" criterion = "0.5.1" float-cmp = "0.10.0" diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index 0fd300cf6e1..f214acdd760 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -1,6 +1,7 @@ // Boa's implementation of the `Temporal.Duration` Builtin Object. use super::{ + get_relative_to_option, options::{get_temporal_unit, TemporalUnitGroup}, DateTimeValues, }; @@ -22,7 +23,7 @@ use crate::{ use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ - options::{RelativeTo, RoundingIncrement, RoundingOptions, TemporalRoundingMode, TemporalUnit}, + options::{RoundingIncrement, RoundingOptions, TemporalRoundingMode, TemporalUnit}, partial::PartialDuration, Duration as InnerDuration, }; @@ -712,8 +713,7 @@ impl Duration { // 10. Let relativeToRecord be ? ToRelativeTemporalObject(roundTo). // 11. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]]. // 12. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]]. - let (plain_relative_to, zoned_relative_to) = - super::to_relative_temporal_object(&round_to, context)?; + let relative_to = get_relative_to_option(&round_to, context)?; // 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). options.increment = @@ -735,13 +735,10 @@ impl Duration { // NOTE: execute step 21 earlier before initial values are shadowed. // 21. If smallestUnitPresent is false and largestUnitPresent is false, then - let rounded_duration = duration.inner.round( - options, - &RelativeTo { - date: plain_relative_to.as_ref(), - zdt: zoned_relative_to.as_ref(), - }, - )?; + let rounded_duration = + duration + .inner + .round_with_provider(options, relative_to, context.tz_provider())?; create_temporal_duration(rounded_duration, None, context).map(Into::into) } diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index 5fe1f9d16d3..366fe7bcfe9 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -311,7 +311,7 @@ impl Instant { let settings = get_difference_settings(&get_options_object(args.get_or_undefined(1))?, context)?; let result = instant.inner.until(&other, settings)?; - create_temporal_duration(result.into(), None, context).map(Into::into) + create_temporal_duration(result, None, context).map(Into::into) } /// 8.3.10 `Temporal.Instant.prototype.since ( other [ , options ] )` @@ -334,7 +334,7 @@ impl Instant { let settings = get_difference_settings(&get_options_object(args.get_or_undefined(1))?, context)?; let result = instant.inner.since(&other, settings)?; - create_temporal_duration(result.into(), None, context).map(Into::into) + create_temporal_duration(result, None, context).map(Into::into) } /// 8.3.11 `Temporal.Instant.prototype.round ( roundTo )` diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index bb814a0a6e1..3e3b237d946 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -31,16 +31,16 @@ pub use self::{ use crate::value::JsVariant; use crate::{ - builtins::{iterable::IteratorRecord, BuiltInBuilder, BuiltInObject, IntrinsicObject}, + builtins::{BuiltInBuilder, BuiltInObject, IntrinsicObject}, context::intrinsics::Intrinsics, js_string, property::Attribute, realm::Realm, string::StaticJsStrings, - value::Type, Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; +use temporal_rs::options::RelativeTo; use temporal_rs::{ primitive::FiniteF64, PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime, NS_PER_DAY, @@ -57,7 +57,6 @@ pub(crate) fn ns_min_instant() -> JsBigInt { } // An enum representing common fields across `Temporal` objects. -#[allow(unused)] pub(crate) enum DateTimeValues { Year, Month, @@ -95,27 +94,22 @@ impl IntrinsicObject for Temporal { .static_property( js_string!("Now"), realm.intrinsics().objects().now(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, - ) - .static_property( - js_string!("Calendar"), - realm.intrinsics().constructors().calendar().constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("Duration"), realm.intrinsics().constructors().duration().constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("Instant"), realm.intrinsics().constructors().instant().constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("PlainDate"), realm.intrinsics().constructors().plain_date().constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("PlainDateTime"), @@ -124,7 +118,7 @@ impl IntrinsicObject for Temporal { .constructors() .plain_date_time() .constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("PlainMonthDay"), @@ -133,12 +127,12 @@ impl IntrinsicObject for Temporal { .constructors() .plain_month_day() .constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("PlainTime"), realm.intrinsics().constructors().plain_time().constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("PlainYearMonth"), @@ -147,12 +141,7 @@ impl IntrinsicObject for Temporal { .constructors() .plain_year_month() .constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, - ) - .static_property( - js_string!("TimeZone"), - realm.intrinsics().constructors().time_zone().constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .static_property( js_string!("ZonedDateTime"), @@ -161,7 +150,7 @@ impl IntrinsicObject for Temporal { .constructors() .zoned_date_time() .constructor(), - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .build(); } @@ -181,38 +170,71 @@ fn to_zero_padded_decimal_string(n: u64, min_length: usize) -> String { format!("{n:0min_length$}") } -/// Abstract Operation 13.1 [`IteratorToListOfType`][proposal] -/// -/// [proposal]: https://tc39.es/proposal-temporal/#sec-iteratortolistoftype -pub(crate) fn _iterator_to_list_of_types( - iterator: &mut IteratorRecord, - element_types: &[Type], +pub(crate) fn get_relative_to_option( + options: &JsObject, context: &mut Context, -) -> JsResult> { - // 1. Let values be a new empty List. - let mut values = Vec::new(); - - // 2. Repeat, - // a. Let next be ? IteratorStepValue(iteratorRecord). - while let Some(next) = iterator.step_value(context)? { - // c. If Type(next) is not an element of elementTypes, then - - if element_types.contains(&next.get_type()) { - // i. Let completion be ThrowCompletion(a newly created TypeError object). - let completion = JsNativeError::typ() - .with_message("IteratorNext is not within allowed type values."); - - // ii. Return ? IteratorClose(iteratorRecord, completion). - let _never = iterator.close(Err(completion.into()), context)?; +) -> JsResult> { + // Let value be ? Get(options, "relativeTo"). + let value = options.get(js_string!("relativeTo"), context)?; + // 2. If value is undefined, return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: undefined }. + if value.is_undefined() { + return Ok(None); + } + // 3. Let offsetBehaviour be option. + // 4. Let matchBehaviour be match-exactly. + // 5. If value is an Object, then + if let Some(object) = value.as_object() { + // a. If value has an [[InitializedTemporalZonedDateTime]] internal slot, then + if let Some(zdt) = object.downcast_ref::() { + // i. Return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: value }. + return Ok(Some(RelativeTo::ZonedDateTime(zdt.inner.clone()))); + // b. If value has an [[InitializedTemporalDate]] internal slot, then + } else if let Some(date) = object.downcast_ref::() { + // i. Return the Record { [[PlainRelativeTo]]: value, [[ZonedRelativeTo]]: undefined }. + return Ok(Some(RelativeTo::PlainDate(date.inner.clone()))); + // c. If value has an [[InitializedTemporalDateTime]] internal slot, then + } else if let Some(dt) = object.downcast_ref::() { + // i. Let plainDate be ! CreateTemporalDate(value.[[ISODateTime]].[[ISODate]], value.[[Calendar]]). + // ii. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined }. + return Ok(Some(RelativeTo::PlainDate(dt.inner.clone().into()))); } - - // d. Append next to the end of the List values. - values.push(next); + // d. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(value). + // e. Let fields be ? PrepareCalendarFields(calendar, value, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond, offset, time-zone », «»). + let partial = to_partial_zoneddatetime(object, context)?; + // f. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, constrain). + // g. Let timeZone be fields.[[TimeZone]]. + // h. Let offsetString be fields.[[OffsetString]]. + // i. If offsetString is unset, then + // i. Set offsetBehaviour to wall. + // j. Let isoDate be result.[[ISODate]]. + if partial.timezone.is_none() { + return Ok(Some(RelativeTo::PlainDate(TemporalDate::from_partial( + partial.date, + None, + )?))); + } + // k. Let time be result.[[Time]]. + let zdt = TemporalZonedDateTime::from_partial_with_provider( + partial, + None, + None, + None, + context.tz_provider(), + )?; + return Ok(Some(RelativeTo::ZonedDateTime(zdt))); } - - // b. If next is done, then - // i. Return values. - Ok(values) + // 6. Else, + // a. If value is not a String, throw a TypeError exception. + let Some(relative_to_str) = value.as_string() else { + return Err(JsNativeError::typ() + .with_message("relativeTo must be an object or string.") + .into()); + }; + // Steps 7-12 are handled by temporal_rs + Ok(Some(RelativeTo::try_from_str_with_provider( + &relative_to_str.to_std_string_escaped(), + context.tz_provider(), + )?)) } type RelativeTemporalObjectResult = JsResult<(Option, Option)>; diff --git a/core/engine/src/builtins/temporal/now.rs b/core/engine/src/builtins/temporal/now.rs index f16c9f79411..68e19f196cb 100644 --- a/core/engine/src/builtins/temporal/now.rs +++ b/core/engine/src/builtins/temporal/now.rs @@ -14,8 +14,9 @@ use boa_profiler::Profiler; use temporal_rs::{Now as NowInner, TimeZone}; use super::{ - create_temporal_datetime, create_temporal_instant, ns_max_instant, ns_min_instant, - time_zone::default_time_zone, to_temporal_timezone_identifier, + create_temporal_date, create_temporal_datetime, create_temporal_instant, create_temporal_time, + create_temporal_zoneddatetime, ns_max_instant, ns_min_instant, time_zone::default_time_zone, + to_temporal_timezone_identifier, }; /// JavaScript `Temporal.Now` object. @@ -41,8 +42,9 @@ impl IntrinsicObject for Now { .static_method(Self::time_zone_id, js_string!("timeZoneId"), 0) .static_method(Self::instant, js_string!("instant"), 0) .static_method(Self::plain_datetime, js_string!("plainDateTimeISO"), 0) - .static_method(Self::zoned_date_time, js_string!("zonedDateTimeISO"), 0) + .static_method(Self::zoneddatetime, js_string!("zonedDateTimeISO"), 0) .static_method(Self::plain_date, js_string!("plainDateISO"), 0) + .static_method(Self::plain_time, js_string!("plainTimeISO"), 0) .build(); } @@ -83,7 +85,7 @@ impl Now { .map(|v| to_temporal_timezone_identifier(v, context)) .transpose()?; create_temporal_datetime( - NowInner::plain_date_time_with_provider(tz, context.tz_provider())?, + NowInner::plain_datetime_iso_with_provider(tz, context.tz_provider())?, None, context, ) @@ -91,17 +93,32 @@ impl Now { } /// `Temporal.Now.zonedDateTime` - fn zoned_date_time(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { - Err(JsNativeError::error() - .with_message("not yet implemented.") - .into()) + fn zoneddatetime(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { + let timezone = args + .first() + .map(|v| to_temporal_timezone_identifier(v, context)) + .transpose()?; + let zdt = NowInner::zoneddatetime_iso(timezone)?; + create_temporal_zoneddatetime(zdt, None, context).map(Into::into) } /// `Temporal.Now.plainDateISO` - fn plain_date(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { - Err(JsNativeError::error() - .with_message("not yet implemented.") - .into()) + fn plain_date(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { + let tz = args + .first() + .map(|v| to_temporal_timezone_identifier(v, context)) + .transpose()?; + let pd = NowInner::plain_date_iso_with_provider(tz, context.tz_provider())?; + create_temporal_date(pd, None, context).map(Into::into) + } + + fn plain_time(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { + let tz = args + .first() + .map(|v| to_temporal_timezone_identifier(v, context)) + .transpose()?; + let pt = NowInner::plain_time_iso_with_provider(tz, context.tz_provider())?; + create_temporal_time(pt, None, context).map(Into::into) } } diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index 8b914b4e85f..a173a320c74 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -1,5 +1,4 @@ //! Boa's implementation of the ECMAScript `Temporal.PlainDate` builtin object. -#![allow(dead_code, unused_variables)] // TODO (nekevss): DOCS DOCS AND MORE DOCS @@ -257,7 +256,7 @@ impl BuiltInConstructor for PlainDate { .as_integer_with_truncation::(); let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(3))?; - let inner = InnerDate::try_new(year, month.into(), day.into(), calendar_slot)?; + let inner = InnerDate::try_new(year, month, day, calendar_slot)?; Ok(create_temporal_date(inner, Some(new_target), context)?.into()) } @@ -267,7 +266,7 @@ impl BuiltInConstructor for PlainDate { impl PlainDate { /// 3.3.3 get `Temporal.PlainDate.prototype.calendarId` - fn get_calendar_id(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_calendar_id(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let date = this .as_object() .and_then(JsObject::downcast_ref::) @@ -279,7 +278,7 @@ impl PlainDate { } /// 3.3.4 get `Temporal.PlainDate.prototype.year` - fn get_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -294,7 +293,7 @@ impl PlainDate { } /// 3.3.5 get `Temporal.PlainDate.prototype.month` - fn get_month(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -309,7 +308,7 @@ impl PlainDate { } /// 3.3.6 get Temporal.PlainDate.prototype.monthCode - fn get_month_code(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_month_code(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -324,7 +323,7 @@ impl PlainDate { } /// 3.3.7 get `Temporal.PlainDate.prototype.day` - fn get_day(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_day(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -339,7 +338,7 @@ impl PlainDate { } /// 3.3.8 get `Temporal.PlainDate.prototype.dayOfWeek` - fn get_day_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_day_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -354,7 +353,7 @@ impl PlainDate { } /// 3.3.9 get `Temporal.PlainDate.prototype.dayOfYear` - fn get_day_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_day_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -369,7 +368,7 @@ impl PlainDate { } /// 3.3.10 get `Temporal.PlainDate.prototype.weekOfYear` - fn get_week_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_week_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -384,7 +383,7 @@ impl PlainDate { } /// 3.3.11 get `Temporal.PlainDate.prototype.yearOfWeek` - fn get_year_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_year_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -399,7 +398,7 @@ impl PlainDate { } /// 3.3.12 get `Temporal.PlainDate.prototype.daysInWeek` - fn get_days_in_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_days_in_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -414,11 +413,7 @@ impl PlainDate { } /// 3.3.13 get `Temporal.PlainDate.prototype.daysInMonth` - fn get_days_in_month( - this: &JsValue, - _: &[JsValue], - context: &mut Context, - ) -> JsResult { + fn get_days_in_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -433,7 +428,7 @@ impl PlainDate { } /// 3.3.14 get `Temporal.PlainDate.prototype.daysInYear` - fn get_days_in_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_days_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -448,11 +443,7 @@ impl PlainDate { } /// 3.3.15 get `Temporal.PlainDate.prototype.monthsInYear` - fn get_months_in_year( - this: &JsValue, - _: &[JsValue], - context: &mut Context, - ) -> JsResult { + fn get_months_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -467,7 +458,7 @@ impl PlainDate { } /// 3.3.16 get `Temporal.PlainDate.prototype.inLeapYear` - fn get_in_leap_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + fn get_in_leap_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let obj = this .as_object() .ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?; @@ -512,13 +503,13 @@ impl PlainDate { // ==== `PlainDate.prototype` method implementation ==== impl PlainDate { - fn to_plain_year_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { + fn to_plain_year_month(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) } - fn to_plain_month_day(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { + fn to_plain_month_day(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { Err(JsNativeError::error() .with_message("not yet implemented.") .into()) @@ -748,13 +739,6 @@ impl PlainDate { // -- `PlainDate` Abstract Operations -- -impl PlainDate { - /// Utitily function for translating a `Temporal.PlainDate` into a `JsObject`. - pub(crate) fn as_object(&self, context: &mut Context) -> JsResult { - create_temporal_date(self.inner.clone(), None, context) - } -} - // 3.5.2 `CreateIsoDateRecord` // Implemented on `IsoDateRecord` @@ -812,7 +796,7 @@ pub(crate) fn to_temporal_date( if let Some(object) = item.as_object() { // a. If item has an [[InitializedTemporalDate]] internal slot, then if let Some(date) = object.downcast_ref::() { - let options_obj = get_options_object(&options)?; + let _options_obj = get_options_object(&options)?; return Ok(date.inner.clone()); // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then } else if let Some(zdt) = object.downcast_ref::() { @@ -824,9 +808,10 @@ pub(crate) fn to_temporal_date( // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]). // iii. Let plainDateTime be ? GetPlainDateTimeFor(item.[[TimeZone]], instant, item.[[Calendar]]). // iv. Return ! CreateTemporalDate(plainDateTime.[[ISOYear]], plainDateTime.[[ISOMonth]], plainDateTime.[[ISODay]], plainDateTime.[[Calendar]]). - return Err(JsNativeError::error() - .with_message("Not yet implemented.") - .into()); + return zdt + .inner + .to_plain_date_with_provider(context.tz_provider()) + .map_err(Into::into); // c. If item has an [[InitializedTemporalDateTime]] internal slot, then } else if let Some(dt) = object.downcast_ref::() { let options_obj = get_options_object(&options)?; @@ -885,7 +870,7 @@ pub(crate) fn to_temporal_date( // 8. Let resolvedOptions be ? GetOptionsObject(options). let resolved_options = get_options_object(&options)?; // 9. Perform ? GetTemporalOverflowOption(resolvedOptions). - let overflow = + let _overflow = get_option::(&resolved_options, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); @@ -898,6 +883,7 @@ pub(crate) fn to_partial_date_record( partial_object: &JsObject, context: &mut Context, ) -> JsResult { + let calendar = get_temporal_calendar_slot_value_with_default(partial_object, context)?; // TODO: Most likely need to use an iterator to handle. let day = partial_object .get(js_string!("day"), context)? @@ -967,5 +953,6 @@ pub(crate) fn to_partial_date_record( day, era, era_year, + calendar, }) } diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index f25c41f2f91..7bd400448e2 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -369,14 +369,14 @@ impl BuiltInConstructor for PlainDateTime { let dt = InnerDateTime::new( iso_year, - iso_month.into(), - iso_day.into(), - hour.into(), - minute.into(), - second.into(), - millisecond.into(), - microsecond.into(), - nanosecond.into(), + iso_month, + iso_day, + hour, + minute, + second, + millisecond, + microsecond, + nanosecond, calendar_slot, )?; @@ -1004,15 +1004,16 @@ pub(crate) fn to_temporal_datetime( // i. Return item. return Ok(dt.inner.clone()); // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then - } else if let Some(_zdt) = object.downcast_ref::() { + } else if let Some(zdt) = object.downcast_ref::() { // i. Perform ? GetTemporalOverflowOption(resolvedOptions). let _ = get_option::(&options, js_string!("overflow"), context)?; // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]). // iii. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(item.[[TimeZone]], « get-offset-nanoseconds-for »). // iv. Return ? GetPlainDateTimeFor(timeZoneRec, instant, item.[[Calendar]]). - return Err(JsNativeError::error() - .with_message("Not yet implemented.") - .into()); + return zdt + .inner + .to_plain_datetime_with_provider(context.tz_provider()) + .map_err(Into::into); // c. If item has an [[InitializedTemporalDate]] internal slot, then } else if let Some(date) = object.downcast_ref::() { // i. Perform ? GetTemporalOverflowOption(resolvedOptions). @@ -1020,8 +1021,8 @@ pub(crate) fn to_temporal_datetime( // ii. Return ? CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0, item.[[Calendar]]). return Ok(InnerDateTime::new( date.inner.iso_year(), - date.inner.iso_month().into(), - date.inner.iso_day().into(), + date.inner.iso_month(), + date.inner.iso_day(), 0, 0, 0, @@ -1068,14 +1069,14 @@ pub(crate) fn to_temporal_datetime( return InnerDateTime::new( date.iso_year(), - date.iso_month().into(), - date.iso_day().into(), - time.hour().into(), - time.minute().into(), - time.second().into(), - time.millisecond().into(), - time.microsecond().into(), - time.nanosecond().into(), + date.iso_month(), + date.iso_day(), + time.hour(), + time.minute(), + time.second(), + time.millisecond(), + time.microsecond(), + time.nanosecond(), calendar, ) .map_err(Into::into); diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index c665d775126..26f20b203b0 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -22,7 +22,7 @@ use boa_profiler::Profiler; use temporal_rs::{ options::{ArithmeticOverflow, CalendarName}, partial::PartialDate, - PlainDateTime, PlainMonthDay as InnerMonthDay, TinyAsciiStr, + PlainMonthDay as InnerMonthDay, TinyAsciiStr, }; use super::{calendar::to_temporal_calendar_slot_value, DateTimeValues}; @@ -219,8 +219,8 @@ impl BuiltInConstructor for PlainMonthDay { let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; let inner = InnerMonthDay::new_with_overflow( - m.into(), - d.into(), + m, + d, calendar, ArithmeticOverflow::Constrain, ref_year, @@ -274,11 +274,6 @@ pub(crate) fn create_temporal_month_day( ) -> JsResult { // 1. If IsValidISODate(referenceISOYear, isoMonth, isoDay) is false, throw a RangeError exception. // 2. If ISODateTimeWithinLimits(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception. - if !PlainDateTime::validate(&inner) { - return Err(JsNativeError::range() - .with_message("PlainMonthDay does not hold a valid ISO date time.") - .into()); - } // 3. If newTarget is not present, set newTarget to %Temporal.PlainMonthDay%. let new_target = if let Some(target) = new_target { @@ -334,9 +329,8 @@ fn to_temporal_month_day( .get_v(js_string!("day"), context)? .map(|v| { let finite = v.to_finitef64(context)?; - // TODO: Update to the below to u8 after temporal_rs change finite - .as_positive_integer_with_truncation::() + .as_positive_integer_with_truncation::() .map_err(JsError::from) }) .transpose()?; @@ -345,9 +339,8 @@ fn to_temporal_month_day( .get_v(js_string!("month"), context)? .map(|v| { let finite = v.to_finitef64(context)?; - // TODO: Update to the below to u8 after temporal_rs change finite - .as_positive_integer_with_truncation::() + .as_positive_integer_with_truncation::() .map_err(JsError::from) }) .transpose()?; diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index e6b015f0b15..35cbe4a6742 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -189,14 +189,8 @@ impl BuiltInConstructor for PlainTime { Ok(finite.as_integer_with_truncation::()) })?; - let inner = PlainTimeInner::new( - hour.into(), - minute.into(), - second.into(), - millisecond.into(), - microsecond.into(), - nanosecond.into(), - )?; + let inner = + PlainTimeInner::new(hour, minute, second, millisecond, microsecond, nanosecond)?; // 8. Return ? CreateTemporalTime(hour, minute, second, millisecond, microsecond, nanosecond, NewTarget). create_temporal_time(inner, Some(new_target), context).map(Into::into) @@ -655,7 +649,7 @@ pub(crate) fn to_temporal_time( get_option::(&options, js_string!("overflow"), context)?; return Ok(time.inner); // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then - } else if let Some(_zdt) = object.downcast_ref::() { + } else if let Some(zdt) = object.downcast_ref::() { // i. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]). // ii. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(item.[[TimeZone]], « get-offset-nanoseconds-for »). // iii. Let plainDateTime be ? GetPlainDateTimeFor(timeZoneRec, instant, item.[[Calendar]]). @@ -665,9 +659,10 @@ pub(crate) fn to_temporal_time( let options = get_options_object(options)?; let _overflow = get_option::(&options, js_string!("overflow"), context)?; - return Err(JsNativeError::range() - .with_message("Not yet implemented.") - .into()); + return zdt + .inner + .to_plain_time_with_provider(context.tz_provider()) + .map_err(Into::into); // c. If item has an [[InitializedTemporalDateTime]] internal slot, then } else if let Some(dt) = object.downcast_ref::() { // i. Return ! CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]], 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 4a075a21c5a..389858c044b 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -183,7 +183,7 @@ impl BuiltInConstructor for PlainYearMonth { let m = args .get_or_undefined(1) .to_finitef64(context)? - .as_integer_with_truncation::(); + .as_integer_with_truncation::(); // 5. Let calendar be ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; @@ -247,7 +247,7 @@ impl PlainYearMonth { .get_v(js_string!("month"), context)? .map(|v| { let finite = v.to_finitef64(context)?; - Ok::(finite.as_integer_with_truncation::()) + Ok::(finite.as_integer_with_truncation::()) }) .transpose()? .unwrap_or_default(); @@ -256,7 +256,7 @@ impl PlainYearMonth { .get_v(js_string!("day"), context)? .map(|v| { let finite = v.to_finitef64(context)?; - Ok::(finite.as_integer_with_truncation::()) + Ok::(finite.as_integer_with_truncation::()) }) .transpose()?; diff --git a/core/engine/src/builtins/temporal/zoneddatetime/mod.rs b/core/engine/src/builtins/temporal/zoneddatetime/mod.rs index bb72c2fa5ad..5d989d086f6 100644 --- a/core/engine/src/builtins/temporal/zoneddatetime/mod.rs +++ b/core/engine/src/builtins/temporal/zoneddatetime/mod.rs @@ -25,9 +25,9 @@ use temporal_rs::{ }; use super::{ - calendar::{get_temporal_calendar_slot_value_with_default, to_temporal_calendar_slot_value}, - create_temporal_date, create_temporal_datetime, create_temporal_instant, create_temporal_time, - to_partial_date_record, to_partial_time_record, to_temporal_duration, to_temporal_time, + calendar::to_temporal_calendar_slot_value, create_temporal_date, create_temporal_datetime, + create_temporal_instant, create_temporal_time, to_partial_date_record, to_partial_time_record, + to_temporal_duration, to_temporal_time, }; /// The `Temporal.ZonedDateTime` object. @@ -246,13 +246,13 @@ impl IntrinsicObject for ZonedDateTime { Attribute::CONFIGURABLE, ) .accessor( - js_string!("epochMillisecond"), + js_string!("epochMilliseconds"), Some(get_epoch_millisecond), None, Attribute::CONFIGURABLE, ) .accessor( - js_string!("epochNanosecond"), + js_string!("epochNanoseconds"), Some(get_epoch_nanosecond), None, Attribute::CONFIGURABLE, @@ -1083,32 +1083,8 @@ pub(crate) fn to_temporal_zoneddatetime( // vi. Return ! CreateTemporalZonedDateTime(item.[[EpochNanoseconds]], item.[[TimeZone]], item.[[Calendar]]). return Ok(zdt.inner.clone()); } - // b. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item). - let calendar = get_temporal_calendar_slot_value_with_default(object, context)?; - // c. Let fields be ? PrepareCalendarFields(calendar, item, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond, offset, time-zone », « time-zone »). - let date = to_partial_date_record(object, context)?; - let time = to_partial_time_record(object, context)?; - // d. Let timeZone be fields.[[TimeZone]]. - let timezone = object - .get(js_string!("timeZone"), context)? - .map(|v| { - // TODO: to_temporal_timezone_identifier - to_temporal_timezone_identifier(v, context) - }) - .transpose()? - .unwrap_or_default(); - // e. Let offsetString be fields.[[OffsetString]]. - let offset = object - .get(js_string!("offset"), context)? - .map(|v| to_offset_string(v, context)) - .transpose()?; - let partial = PartialZonedDateTime { - date, - time, - offset, - timezone, - }; - // f. If offsetString is unset, then + let partial = to_partial_zoneddatetime(object, context)?; + // f. If offsetString is unset, the // i. Set offsetBehaviour to wall. // g. Let resolvedOptions be ? GetOptionsObject(options). let options = get_options_object(&options.unwrap_or_default())?; @@ -1126,7 +1102,6 @@ pub(crate) fn to_temporal_zoneddatetime( // m. Let time be result.[[Time]]. Ok(ZonedDateTimeInner::from_partial_with_provider( partial, - Some(calendar), overflow, disambiguation, offset_option, @@ -1228,3 +1203,29 @@ fn to_offset_string(value: &JsValue, context: &mut Context) -> JsResult // 4. Return offset. Ok(result) } + +pub(crate) fn to_partial_zoneddatetime( + object: &JsObject, + context: &mut Context, +) -> JsResult { + // b. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item). + // c. Let fields be ? PrepareCalendarFields(calendar, item, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond, offset, time-zone », « time-zone »). + let date = to_partial_date_record(object, context)?; + let time = to_partial_time_record(object, context)?; + // d. Let timeZone be fields.[[TimeZone]]. + let timezone = object + .get(js_string!("timeZone"), context)? + .map(|v| to_temporal_timezone_identifier(v, context)) + .transpose()?; + // e. Let offsetString be fields.[[OffsetString]]. + let offset = object + .get(js_string!("offset"), context)? + .map(|v| to_offset_string(v, context)) + .transpose()?; + Ok(PartialZonedDateTime { + date, + time, + offset, + timezone, + }) +}