Skip to content

Commit

Permalink
Updates to temporal_rs version and temporal methods (#3900)
Browse files Browse the repository at this point in the history
* Updates to temporal_rs version and temporal methods

* Apply review feedback for relativeTo

* Forgot Date.prototype.toPlainDateTime

* Fix doc on toPlainDateTime
  • Loading branch information
nekevss authored Jul 8, 2024
1 parent 36eeea1 commit 5889a76
Show file tree
Hide file tree
Showing 7 changed files with 394 additions and 41 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ intrusive-collections = "0.9.6"
cfg-if = "1.0.0"
either = "1.13.0"
sys-locale = "0.3.1"
temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "cf70b50f90865d2c00fb994b7adf8b9e1bd837b8" }
temporal_rs = "0.0.3"
web-time = "1.1.0"
criterion = "0.5.1"
float-cmp = "0.9.0"
Expand Down
66 changes: 57 additions & 9 deletions core/engine/src/builtins/temporal/duration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl IntrinsicObject for Duration {
None,
Attribute::CONFIGURABLE,
)
.static_method(Self::from, js_string!("from"), 1)
.method(Self::with, js_string!("with"), 1)
.method(Self::negated, js_string!("negated"), 0)
.method(Self::abs, js_string!("abs"), 0)
Expand Down Expand Up @@ -412,7 +413,26 @@ impl Duration {
}
}

// -- Duration Method implementations --
// ==== Duration methods implementations ====

impl Duration {
fn from(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let item = args.get_or_undefined(0);
// 1. If item is an Object and item has an [[InitializedTemporalDuration]] internal slot, then
if let Some(duration) = item.as_object().and_then(JsObject::downcast_ref::<Self>) {
// a. Return ! CreateTemporalDuration(item.[[Years]], item.[[Months]], item.[[Weeks]],
// item.[[Days]], item.[[Hours]], item.[[Minutes]], item.[[Seconds]], item.[[Milliseconds]],
// item.[[Microseconds]], item.[[Nanoseconds]]).
return create_temporal_duration(duration.inner, None, context).map(Into::into);
}

// 2. Return ? ToTemporalDuration(item).
create_temporal_duration(to_temporal_duration_record(item, context)?, None, context)
.map(Into::into)
}
}

// ==== Duration.prototype method implementations ====

impl Duration {
/// 7.3.15 `Temporal.Duration.prototype.with ( temporalDurationLike )`
Expand Down Expand Up @@ -581,17 +601,45 @@ impl Duration {
}

/// 7.3.18 `Temporal.Duration.prototype.add ( other [ , options ] )`
pub(crate) fn add(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::range()
.with_message("not yet implemented.")
.into())
pub(crate) fn add(
this: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
// 1.Let duration be the this value.
// 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
let duration = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("this value must be a Duration object.")
})?;

// 3. Return ? AddDurations(add, duration, other).
let other = to_temporal_duration_record(args.get_or_undefined(0), context)?;

create_temporal_duration(duration.inner.add(&other)?, None, context).map(Into::into)
}

/// 7.3.19 `Temporal.Duration.prototype.subtract ( other [ , options ] )`
pub(crate) fn subtract(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::range()
.with_message("not yet implemented.")
.into())
pub(crate) fn subtract(
this: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
// 1.Let duration be the this value.
// 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
let duration = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("this value must be a Duration object.")
})?;

let other = to_temporal_duration_record(args.get_or_undefined(0), context)?;

// 3. Return ? AddDurations(add, duration, other).
create_temporal_duration(duration.inner.subtract(&other)?, None, context).map(Into::into)
}

/// 7.3.20 `Temporal.Duration.prototype.round ( roundTo )`
Expand Down
19 changes: 11 additions & 8 deletions core/engine/src/builtins/temporal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{
realm::Realm,
string::StaticJsStrings,
value::Type,
Context, JsBigInt, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
};
use boa_macros::js_str;
use boa_profiler::Profiler;
Expand Down Expand Up @@ -250,15 +250,18 @@ pub(crate) fn to_relative_temporal_object(
) -> RelativeTemporalObjectResult {
let relative_to = options.get(PropertyKey::from(js_str!("relativeTo")), context)?;
let plain_date = match relative_to {
JsValue::String(relative_to_str) => Some(relative_to_str.into()),
JsValue::Object(relative_to_obj) => Some(relative_to_obj.into()),
_ => None,
}
.map(|plane_date| Ok::<_, JsError>(to_temporal_date(&plane_date, None, context)?.inner))
.transpose()?;
JsValue::String(relative_to_str) => JsValue::from(relative_to_str),
JsValue::Object(relative_to_obj) => JsValue::from(relative_to_obj),
_ => {
return Err(JsNativeError::typ()
.with_message("Invalid type for converting to relativeTo object")
.into())
}
};
let plain_date = to_temporal_date(&plain_date, None, context)?;

// TODO: Implement TemporalZonedDateTime conversion when ZonedDateTime is implemented
Ok((plain_date, None))
Ok((Some(plain_date), None))
}

// 13.22 `LargerOfTwoTemporalUnits ( u1, u2 )`
Expand Down
85 changes: 69 additions & 16 deletions core/engine/src/builtins/temporal/plain_date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use temporal_rs::{
};

use super::{
calendar, create_temporal_duration, options::get_difference_settings,
to_temporal_duration_record, PlainDateTime, ZonedDateTime,
calendar, create_temporal_datetime, create_temporal_duration, options::get_difference_settings,
to_temporal_duration_record, to_temporal_time, PlainDateTime, ZonedDateTime,
};

/// The `Temporal.PlainDate` object.
Expand Down Expand Up @@ -212,6 +212,7 @@ impl IntrinsicObject for PlainDate {
None,
Attribute::CONFIGURABLE,
)
.static_method(Self::from, js_string!("from"), 2)
.method(Self::to_plain_year_month, js_string!("toPlainYearMonth"), 0)
.method(Self::to_plain_month_day, js_string!("toPlainMonthDay"), 0)
.method(Self::get_iso_fields, js_string!("getISOFields"), 0)
Expand All @@ -222,6 +223,7 @@ impl IntrinsicObject for PlainDate {
.method(Self::until, js_string!("until"), 2)
.method(Self::since, js_string!("since"), 2)
.method(Self::equals, js_string!("equals"), 1)
.method(Self::to_plain_datetime, js_string!("toPlainDateTime"), 1)
.build();
}

Expand Down Expand Up @@ -276,7 +278,7 @@ impl PlainDate {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;

Ok(JsString::from(date.inner.calendar().identifier()?).into())
Ok(JsString::from(date.inner.calendar().identifier()).into())
}

/// 3.3.4 get `Temporal.PlainDate.prototype.year`
Expand Down Expand Up @@ -483,6 +485,28 @@ impl PlainDate {
}
}

// ==== `PlainDate` method implementations ====

impl PlainDate {
fn from(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let item = args.get_or_undefined(0);
let options = args.get(1);

if let Some(date) = item.as_object().and_then(JsObject::downcast_ref::<Self>) {
let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?;
let _ = get_option::<ArithmeticOverflow>(&options, js_str!("overflow"), context)?;
return create_temporal_date(date.inner.clone(), None, context).map(Into::into);
}

create_temporal_date(
to_temporal_date(item, options.cloned(), context)?,
None,
context,
)
.map(Into::into)
}
}

// ==== `PlainDate.prototype` method implementation ====

impl PlainDate {
Expand Down Expand Up @@ -514,7 +538,7 @@ impl PlainDate {
// 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar", temporalDate.[[Calendar]]).
fields.create_data_property_or_throw(
js_str!("calendar"),
JsString::from(date.inner.calendar().identifier()?),
JsString::from(date.inner.calendar().identifier()),
context,
)?;
// 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay", 𝔽(temporalDate.[[ISODay]])).
Expand Down Expand Up @@ -606,8 +630,7 @@ impl PlainDate {
let options = get_options_object(args.get_or_undefined(1))?;
let settings = get_difference_settings(&options, context)?;

create_temporal_duration(date.inner.until(&other.inner, settings)?, None, context)
.map(Into::into)
create_temporal_duration(date.inner.until(&other, settings)?, None, context).map(Into::into)
}

fn since(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Expand All @@ -626,14 +649,44 @@ impl PlainDate {
let options = get_options_object(args.get_or_undefined(1))?;
let settings = get_difference_settings(&options, context)?;

create_temporal_duration(date.inner.since(&other.inner, settings)?, None, context)
.map(Into::into)
create_temporal_duration(date.inner.since(&other, settings)?, None, context).map(Into::into)
}

fn equals(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
fn equals(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;

let other = to_temporal_date(args.get_or_undefined(0), None, context)?;

Ok((date.inner == other).into())
}

/// 3.3.30 `Temporal.PlainDate.prototype.toPlainDateTime ( [ temporalTime ] )`
fn to_plain_datetime(
this: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
// 1. Let temporalDate be the this value.
// 2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
let date = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;

// 3. Set temporalTime to ? ToTemporalTimeOrMidnight(temporalTime).
let time = args
.first()
.map(|v| to_temporal_time(v, None, context))
.transpose()?;
// 4. Return ? CreateTemporalDateTime(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], temporalDate.[[Calendar]]).
create_temporal_datetime(date.inner.to_date_time(time)?, None, context).map(Into::into)
}
}

Expand Down Expand Up @@ -699,7 +752,7 @@ pub(crate) fn to_temporal_date(
item: &JsValue,
options: Option<JsValue>,
context: &mut Context,
) -> JsResult<PlainDate> {
) -> JsResult<InnerDate> {
// 1. If options is not present, set options to undefined.
let options = options.unwrap_or(JsValue::undefined());

Expand All @@ -711,7 +764,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::<PlainDate>() {
return Ok(PlainDate::new(date.inner.clone()));
return Ok(date.inner.clone());
// b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
} else if let Some(data) = object.downcast_ref::<ZonedDateTime>() {
return Err(JsNativeError::range()
Expand All @@ -731,7 +784,7 @@ pub(crate) fn to_temporal_date(
let date = InnerDate::from_datetime(date_time.inner());

// ii. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]]).
return Ok(PlainDate::new(date));
return Ok(date);
}

// d. Let calendar be ? GetTemporalCalendarSlotValueWithISODefault(item).
Expand Down Expand Up @@ -763,5 +816,5 @@ pub(crate) fn to_temporal_date(
.parse::<InnerDate>()
.map_err(|err| JsNativeError::range().with_message(err.to_string()))?;

Ok(PlainDate::new(result))
Ok(result)
}
Loading

0 comments on commit 5889a76

Please sign in to comment.