use crate::{
context::intrinsics::StandardConstructors,
object::{
internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsFunction, JsObject,
ObjectData,
},
Context, JsResult, JsString, JsValue,
};
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
#[derive(Debug, Clone, Trace, Finalize)]
pub struct DateTimeFormat {
initialized_date_time_format: bool,
locale: JsString,
calendar: JsString,
numbering_system: JsString,
time_zone: JsString,
weekday: JsString,
era: JsString,
year: JsString,
month: JsString,
day: JsString,
day_period: JsString,
hour: JsString,
minute: JsString,
second: JsString,
fractional_second_digits: JsString,
time_zone_name: JsString,
hour_cycle: JsString,
pattern: JsString,
bound_format: JsString,
}
impl DateTimeFormat {
const NAME: &'static str = "DateTimeFormat";
pub(super) fn init(context: &mut Context) -> JsFunction {
let _timer = Profiler::global().start_event(Self::NAME, "init");
ConstructorBuilder::new(context, Self::constructor)
.name(Self::NAME)
.length(0)
.build()
}
}
impl DateTimeFormat {
pub(crate) fn constructor(
new_target: &JsValue,
_args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let prototype = get_prototype_from_constructor(
new_target,
StandardConstructors::date_time_format,
context,
)?;
let date_time_format = JsObject::from_proto_and_data(
prototype,
ObjectData::date_time_format(Box::new(Self {
initialized_date_time_format: true,
locale: JsString::from("en-US"),
calendar: JsString::from("gregory"),
numbering_system: JsString::from("arab"),
time_zone: JsString::from("UTC"),
weekday: JsString::from("narrow"),
era: JsString::from("narrow"),
year: JsString::from("numeric"),
month: JsString::from("narrow"),
day: JsString::from("numeric"),
day_period: JsString::from("narrow"),
hour: JsString::from("numeric"),
minute: JsString::from("numeric"),
second: JsString::from("numeric"),
fractional_second_digits: JsString::from(""),
time_zone_name: JsString::from(""),
hour_cycle: JsString::from("h24"),
pattern: JsString::from("{hour}:{minute}"),
bound_format: JsString::from("undefined"),
})),
);
Ok(date_time_format.into())
}
}
#[allow(unused)]
#[derive(Debug, PartialEq)]
pub(crate) enum DateTimeReqs {
Date,
Time,
AnyAll,
}
#[allow(unused)]
pub(crate) fn to_date_time_options(
options: &JsValue,
required: &DateTimeReqs,
defaults: &DateTimeReqs,
context: &mut Context,
) -> JsResult<JsObject> {
let options = if options.is_undefined() {
None
} else {
Some(options.to_object(context)?)
};
let options = JsObject::from_proto_and_data(options, ObjectData::ordinary());
let mut need_defaults = true;
if [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(required) {
for property in ["weekday", "year", "month", "day"] {
let value = options.get(property, context)?;
if !value.is_undefined() {
need_defaults = false;
}
}
}
if [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(required) {
for property in [
"dayPeriod",
"hour",
"minute",
"second",
"fractionalSecondDigits",
] {
let value = options.get(property, context)?;
if !value.is_undefined() {
need_defaults = false;
}
}
}
let date_style = options.get("dateStyle", context)?;
let time_style = options.get("timeStyle", context)?;
if !date_style.is_undefined() || !time_style.is_undefined() {
need_defaults = false;
}
if required == &DateTimeReqs::Date && !time_style.is_undefined() {
return context.throw_type_error("'date' is required, but timeStyle was defined");
}
if required == &DateTimeReqs::Time && !date_style.is_undefined() {
return context.throw_type_error("'time' is required, but dateStyle was defined");
}
if need_defaults && [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(defaults) {
for property in ["year", "month", "day"] {
options.create_data_property_or_throw(property, "numeric", context)?;
}
}
if need_defaults && [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(defaults) {
for property in ["hour", "minute", "second"] {
options.create_data_property_or_throw(property, "numeric", context)?;
}
}
Ok(options)
}