use crate::{
builtins::{BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
js_string,
object::internal_methods::get_prototype_from_constructor,
property::Attribute,
realm::Realm,
string::StaticJsStrings,
Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
};
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
use temporal_rs::{
iso::IsoDateSlots,
{
components::{
calendar::{Calendar as InnerCalendar, GetTemporalCalendar},
YearMonth as InnerYearMonth,
},
options::ArithmeticOverflow,
},
};
use super::calendar;
#[derive(Debug, Clone, Trace, Finalize, JsData)]
#[boa_gc(unsafe_empty_trace)] pub struct PlainYearMonth {
pub(crate) inner: InnerYearMonth,
}
impl PlainYearMonth {
pub(crate) fn new(inner: InnerYearMonth) -> Self {
Self { inner }
}
}
impl IsoDateSlots for JsObject<PlainYearMonth> {
fn iso_date(&self) -> temporal_rs::iso::IsoDate {
self.borrow().data().inner.iso_date()
}
}
impl GetTemporalCalendar for JsObject<PlainYearMonth> {
fn get_calendar(&self) -> InnerCalendar {
self.borrow().data().inner.get_calendar()
}
}
impl BuiltInObject for PlainYearMonth {
const NAME: JsString = StaticJsStrings::PLAIN_YM;
}
impl IntrinsicObject for PlainYearMonth {
fn init(realm: &Realm) {
let _timer = Profiler::global().start_event(std::any::type_name::<Self>(), "init");
let get_calendar_id = BuiltInBuilder::callable(realm, Self::get_calendar_id)
.name(js_string!("get calendarId"))
.build();
let get_year = BuiltInBuilder::callable(realm, Self::get_year)
.name(js_string!("get year"))
.build();
let get_month = BuiltInBuilder::callable(realm, Self::get_month)
.name(js_string!("get month"))
.build();
let get_month_code = BuiltInBuilder::callable(realm, Self::get_month_code)
.name(js_string!("get monthCode"))
.build();
let get_days_in_month = BuiltInBuilder::callable(realm, Self::get_days_in_month)
.name(js_string!("get daysInMonth"))
.build();
let get_days_in_year = BuiltInBuilder::callable(realm, Self::get_days_in_year)
.name(js_string!("get daysInYear"))
.build();
let get_months_in_year = BuiltInBuilder::callable(realm, Self::get_months_in_year)
.name(js_string!("get monthsInYear"))
.build();
let get_in_leap_year = BuiltInBuilder::callable(realm, Self::get_in_leap_year)
.name(js_string!("get inLeapYear"))
.build();
BuiltInBuilder::from_standard_constructor::<Self>(realm)
.property(
JsSymbol::to_string_tag(),
Self::NAME,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("calendarId"),
Some(get_calendar_id),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("year"),
Some(get_year),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("month"),
Some(get_month),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("monthCode"),
Some(get_month_code),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("daysInMonth"),
Some(get_days_in_month),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("daysInYear"),
Some(get_days_in_year),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("monthsInYear"),
Some(get_months_in_year),
None,
Attribute::CONFIGURABLE,
)
.accessor(
js_string!("inLeapYear"),
Some(get_in_leap_year),
None,
Attribute::CONFIGURABLE,
)
.method(Self::with, js_string!("with"), 2)
.method(Self::add, js_string!("add"), 2)
.method(Self::subtract, js_string!("subtract"), 2)
.method(Self::until, js_string!("until"), 2)
.method(Self::since, js_string!("since"), 2)
.method(Self::equals, js_string!("equals"), 1)
.build();
}
fn get(intrinsics: &Intrinsics) -> JsObject {
Self::STANDARD_CONSTRUCTOR(intrinsics.constructors()).constructor()
}
}
impl BuiltInConstructor for PlainYearMonth {
const LENGTH: usize = 0;
const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor =
StandardConstructors::plain_year_month;
fn constructor(
new_target: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
if new_target.is_undefined() {
return Err(JsNativeError::typ()
.with_message("NewTarget cannot be undefined when constructing a PlainYearMonth.")
.into());
}
let day = args.get_or_undefined(3);
let ref_day = if day.is_undefined() {
None
} else {
Some(super::to_integer_with_truncation(day, context)?)
};
let y = super::to_integer_with_truncation(args.get_or_undefined(0), context)?;
let m = super::to_integer_with_truncation(args.get_or_undefined(1), context)?;
let calendar = calendar::to_temporal_calendar_slot_value(args.get_or_undefined(2))?;
let inner = InnerYearMonth::new(y, m, ref_day, calendar, ArithmeticOverflow::Reject)?;
create_temporal_year_month(inner, Some(new_target), context)
}
}
impl PlainYearMonth {
fn get_calendar_id(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_year(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_month(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_month_code(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_days_in_year(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_days_in_month(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_months_in_year(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
fn get_in_leap_year(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
}
impl PlainYearMonth {
fn with(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::typ()
.with_message("not yet implemented.")
.into())
}
fn add(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::typ()
.with_message("not yet implemented.")
.into())
}
fn subtract(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::typ()
.with_message("not yet implemented.")
.into())
}
fn until(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::typ()
.with_message("not yet implemented.")
.into())
}
fn since(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::typ()
.with_message("not yet implemented.")
.into())
}
fn equals(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::typ()
.with_message("not yet implemented.")
.into())
}
}
pub(crate) fn create_temporal_year_month(
ym: InnerYearMonth,
new_target: Option<&JsValue>,
context: &mut Context,
) -> JsResult<JsValue> {
let new_target = if let Some(target) = new_target {
target.clone()
} else {
context
.realm()
.intrinsics()
.constructors()
.plain_year_month()
.constructor()
.into()
};
let proto = get_prototype_from_constructor(
&new_target,
StandardConstructors::plain_year_month,
context,
)?;
let obj = JsObject::from_proto_and_data(proto, PlainYearMonth::new(ym));
Ok(obj.into())
}