mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
LibJS: Implement Intl.Locale.prototype.firstDayOfWeek
This is a normative change in the Intl Locale Info spec. See: https://github.com/tc39/proposal-intl-locale-info/commit/f03a814
This commit is contained in:
parent
b5875700e2
commit
a357874c77
7 changed files with 227 additions and 31 deletions
|
@ -191,6 +191,7 @@ namespace JS {
|
|||
P(findLastIndex) \
|
||||
P(findIndex) \
|
||||
P(firstDay) \
|
||||
P(firstDayOfWeek) \
|
||||
P(fixed) \
|
||||
P(flags) \
|
||||
P(flat) \
|
||||
|
|
|
@ -182,6 +182,93 @@ StringView character_direction_of_locale(Locale const& locale_object)
|
|||
return "ltr"sv;
|
||||
}
|
||||
|
||||
// 1.1.8 WeekdayToNumber ( fw ), https://tc39.es/proposal-intl-locale-info/#sec-weekday-to-number
|
||||
// FIXME: Spec issue: The spec definitions of WeekdayToNumber and WeekdayToString are backwards.
|
||||
// https://github.com/tc39/proposal-intl-locale-info/issues/78
|
||||
Optional<u8> weekday_to_number(StringView weekday)
|
||||
{
|
||||
struct WeekdayToNumber {
|
||||
StringView type;
|
||||
u8 number { 0 };
|
||||
};
|
||||
|
||||
// Table 2: First Day Type and Number, https://tc39.es/proposal-intl-locale-info/#table-locale-first-day-type-number
|
||||
static constexpr auto weekday_to_number_table = AK::Array {
|
||||
WeekdayToNumber { "mon"sv, 1 },
|
||||
WeekdayToNumber { "tue"sv, 2 },
|
||||
WeekdayToNumber { "wed"sv, 3 },
|
||||
WeekdayToNumber { "thu"sv, 4 },
|
||||
WeekdayToNumber { "fri"sv, 5 },
|
||||
WeekdayToNumber { "sat"sv, 6 },
|
||||
WeekdayToNumber { "sun"sv, 7 },
|
||||
};
|
||||
|
||||
// 1. For each row of Table 2, except the header row, in table order, do
|
||||
for (auto const& row : weekday_to_number_table) {
|
||||
// a. Let t be the name given in the Type column of the row.
|
||||
auto type = row.type;
|
||||
|
||||
// b. Let n be the name given in the Number column of the row.
|
||||
auto number = row.number;
|
||||
|
||||
// c. If fw is equal to t, return n.
|
||||
if (weekday == type)
|
||||
return number;
|
||||
}
|
||||
|
||||
// 2. Assert: Should not reach here.
|
||||
// FIXME: Spec issue: This is currently reachable if an invalid value is provided as a locale extension,
|
||||
// for example "en-u-fw-100". We return "undefined" for now to avoid crashing.
|
||||
// https://github.com/tc39/proposal-intl-locale-info/issues/78
|
||||
return {};
|
||||
}
|
||||
|
||||
// 1.1.9 WeekdayToString ( fw ), https://tc39.es/proposal-intl-locale-info/#sec-weekday-to-string
|
||||
// FIXME: Spec issue: The spec definitions of WeekdayToNumber and WeekdayToString are backwards.
|
||||
// https://github.com/tc39/proposal-intl-locale-info/issues/78
|
||||
StringView weekday_to_string(StringView weekday)
|
||||
{
|
||||
struct WeekdayToString {
|
||||
StringView value;
|
||||
StringView type;
|
||||
};
|
||||
|
||||
// Table 1: First Day Value and Type, https://tc39.es/proposal-intl-locale-info/#table-locale-first-day-option-type
|
||||
static constexpr auto weekday_to_string_table = AK::Array {
|
||||
WeekdayToString { "mon"sv, "mon"sv },
|
||||
WeekdayToString { "tue"sv, "tue"sv },
|
||||
WeekdayToString { "wed"sv, "wed"sv },
|
||||
WeekdayToString { "thu"sv, "thu"sv },
|
||||
WeekdayToString { "fri"sv, "fri"sv },
|
||||
WeekdayToString { "sat"sv, "sat"sv },
|
||||
WeekdayToString { "sun"sv, "sun"sv },
|
||||
WeekdayToString { "0"sv, "sun"sv },
|
||||
WeekdayToString { "1"sv, "mon"sv },
|
||||
WeekdayToString { "2"sv, "tue"sv },
|
||||
WeekdayToString { "3"sv, "wed"sv },
|
||||
WeekdayToString { "4"sv, "thu"sv },
|
||||
WeekdayToString { "5"sv, "fri"sv },
|
||||
WeekdayToString { "6"sv, "sat"sv },
|
||||
WeekdayToString { "7"sv, "sun"sv },
|
||||
};
|
||||
|
||||
// 1. For each row of Table 1, except the header row, in table order, do
|
||||
for (auto const& row : weekday_to_string_table) {
|
||||
// a. Let v be the name given in the Value column of the row.
|
||||
auto value = row.value;
|
||||
|
||||
// b. Let t be the name given in the Type column of the row.
|
||||
auto type = row.type;
|
||||
|
||||
// c. If fw is equal to v, return t.
|
||||
if (weekday == value)
|
||||
return type;
|
||||
}
|
||||
|
||||
// 2. Assert: Should not reach here.
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
static u8 weekday_to_integer(Optional<::Locale::Weekday> weekday, ::Locale::Weekday falllback)
|
||||
{
|
||||
// NOTE: This fallback will be used if LibUnicode data generation is disabled. Its value should
|
||||
|
@ -224,7 +311,7 @@ static Vector<u8> weekend_of_locale(StringView locale)
|
|||
return weekend;
|
||||
}
|
||||
|
||||
// 1.1.8 WeekInfoOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-week-info-of-locale
|
||||
// 1.1.10 WeekInfoOfLocale ( loc ), https://tc39.es/proposal-intl-locale-info/#sec-week-info-of-locale
|
||||
WeekInfo week_info_of_locale(Locale const& locale_object)
|
||||
{
|
||||
// 1. Let locale be loc.[[Locale]].
|
||||
|
@ -233,12 +320,20 @@ WeekInfo week_info_of_locale(Locale const& locale_object)
|
|||
// 2. Assert: locale matches the unicode_locale_id production.
|
||||
VERIFY(::Locale::parse_unicode_locale_id(locale).has_value());
|
||||
|
||||
// 3. Return a record whose fields are defined by Table 1, with values based on locale.
|
||||
// 3. Let r be a record whose fields are defined by Table 3, with values based on locale.
|
||||
WeekInfo week_info {};
|
||||
week_info.minimal_days = ::Locale::get_locale_minimum_days(locale).value_or(1);
|
||||
week_info.first_day = weekday_to_integer(::Locale::get_locale_first_day(locale), ::Locale::Weekday::Monday);
|
||||
week_info.weekend = weekend_of_locale(locale);
|
||||
|
||||
// 4. Let fw be loc.[[FirstDayOfWeek]].
|
||||
// 5. If fw is not undefined, then
|
||||
if (locale_object.has_first_day_of_week()) {
|
||||
// a. Set r.[[FirstDay]] to fw.
|
||||
week_info.first_day = locale_object.first_day_of_week();
|
||||
}
|
||||
|
||||
// 6. Return r.
|
||||
return week_info;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,13 @@ public:
|
|||
static constexpr auto relevant_extension_keys()
|
||||
{
|
||||
// 14.2.2 Internal slots, https://tc39.es/ecma402/#sec-intl.locale-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "co", "hc", "kf", "kn", "nu" ».
|
||||
// 1.3.2 Internal slots, https://tc39.es/proposal-intl-locale-info/#sec-intl.locale-internal-slots
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "co", "fw", "hc", "kf", "kn", "nu" ».
|
||||
// If %Collator%.[[RelevantExtensionKeys]] does not contain "kf", then remove "kf" from %Locale%.[[RelevantExtensionKeys]].
|
||||
// If %Collator%.[[RelevantExtensionKeys]] does not contain "kn", then remove "kn" from %Locale%.[[RelevantExtensionKeys]].
|
||||
|
||||
// FIXME: We do not yet have an Intl.Collator object. For now, we behave as if "kf" and "kn" exist, as test262 depends on it.
|
||||
return AK::Array { "ca"sv, "co"sv, "hc"sv, "kf"sv, "kn"sv, "nu"sv };
|
||||
return AK::Array { "ca"sv, "co"sv, "fw"sv, "hc"sv, "kf"sv, "kn"sv, "nu"sv };
|
||||
}
|
||||
|
||||
virtual ~Locale() override = default;
|
||||
|
@ -52,6 +53,10 @@ public:
|
|||
String const& collation() const { return m_collation.value(); }
|
||||
void set_collation(String collation) { m_collation = move(collation); }
|
||||
|
||||
bool has_first_day_of_week() const { return m_first_day_of_week.has_value(); }
|
||||
u8 first_day_of_week() const { return m_first_day_of_week.value(); }
|
||||
void set_first_day_of_week(u8 first_day_of_week) { m_first_day_of_week = first_day_of_week; }
|
||||
|
||||
bool has_hour_cycle() const { return m_hour_cycle.has_value(); }
|
||||
String const& hour_cycle() const { return m_hour_cycle.value(); }
|
||||
void set_hour_cycle(String hour_cycle) { m_hour_cycle = move(hour_cycle); }
|
||||
|
@ -70,6 +75,7 @@ private:
|
|||
Optional<String> m_calendar; // [[Calendar]]
|
||||
Optional<String> m_case_first; // [[CaseFirst]]
|
||||
Optional<String> m_collation; // [[Collation]]
|
||||
Optional<u8> m_first_day_of_week; // [[FirstDayOfWeek]]
|
||||
Optional<String> m_hour_cycle; // [[HourCycle]]
|
||||
Optional<String> m_numbering_system; // [[NumberingSystem]]
|
||||
bool m_numeric { false }; // [[Numeric]]
|
||||
|
@ -88,6 +94,8 @@ NonnullGCPtr<Array> hour_cycles_of_locale(VM&, Locale const& locale);
|
|||
NonnullGCPtr<Array> numbering_systems_of_locale(VM&, Locale const&);
|
||||
NonnullGCPtr<Array> time_zones_of_locale(VM&, StringView region);
|
||||
StringView character_direction_of_locale(Locale const&);
|
||||
Optional<u8> weekday_to_number(StringView);
|
||||
StringView weekday_to_string(StringView);
|
||||
WeekInfo week_info_of_locale(Locale const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ struct LocaleAndKeys {
|
|||
String locale;
|
||||
Optional<String> ca;
|
||||
Optional<String> co;
|
||||
Optional<String> fw;
|
||||
Optional<String> hc;
|
||||
Optional<String> kf;
|
||||
Optional<String> kn;
|
||||
|
@ -139,6 +140,8 @@ static LocaleAndKeys apply_unicode_extension_to_tag(StringView tag, LocaleAndKey
|
|||
return value.ca;
|
||||
if (key == "co"sv)
|
||||
return value.co;
|
||||
if (key == "fw"sv)
|
||||
return value.fw;
|
||||
if (key == "hc"sv)
|
||||
return value.hc;
|
||||
if (key == "kf"sv)
|
||||
|
@ -241,6 +244,7 @@ ThrowCompletionOr<Value> LocaleConstructor::call()
|
|||
}
|
||||
|
||||
// 14.1.1 Intl.Locale ( tag [ , options ] ), https://tc39.es/ecma402/#sec-Intl.Locale
|
||||
// 1.2.3 Intl.Locale ( tag [ , options ] ), https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale
|
||||
ThrowCompletionOr<NonnullGCPtr<Object>> LocaleConstructor::construct(FunctionObject& new_target)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
@ -251,7 +255,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> LocaleConstructor::construct(FunctionObj
|
|||
// 2. Let relevantExtensionKeys be %Locale%.[[RelevantExtensionKeys]].
|
||||
auto relevant_extension_keys = Locale::relevant_extension_keys();
|
||||
|
||||
// 3. Let internalSlotsList be « [[InitializedLocale]], [[Locale]], [[Calendar]], [[Collation]], [[HourCycle]], [[NumberingSystem]] ».
|
||||
// 3. Let internalSlotsList be « [[InitializedLocale]], [[Locale]], [[Calendar]], [[Collation]], [[FirstDayOfWeek]], [[HourCycle]], [[NumberingSystem]] ».
|
||||
// 4. If relevantExtensionKeys contains "kf", then
|
||||
// a. Append [[CaseFirst]] as the last element of internalSlotsList.
|
||||
// 5. If relevantExtensionKeys contains "kn", then
|
||||
|
@ -299,51 +303,82 @@ ThrowCompletionOr<NonnullGCPtr<Object>> LocaleConstructor::construct(FunctionObj
|
|||
// 18. Set opt.[[co]] to collation.
|
||||
opt.co = TRY(get_string_option(vm, *options, vm.names.collation, ::Locale::is_type_identifier));
|
||||
|
||||
// 19. Let hc be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined).
|
||||
// 20. Set opt.[[hc]] to hc.
|
||||
// 19. Let fw be ? GetOption(options, "firstDayOfWeek", "string", « "mon", "tue", "wed", "thu", "fri", "sat", "sun", "0", "1", "2", "3", "4", "5", "6", "7" », undefined).
|
||||
auto first_day_of_week = TRY(get_string_option(vm, *options, vm.names.firstDayOfWeek, nullptr, AK::Array { "mon"sv, "tue"sv, "wed"sv, "thu"sv, "fri"sv, "sat"sv, "sun"sv, "0"sv, "1"sv, "2"sv, "3"sv, "4"sv, "5"sv, "6"sv, "7"sv }));
|
||||
|
||||
// 20. Let firstDay be undefined.
|
||||
Optional<String> first_day_string;
|
||||
|
||||
// 21. If fw is not undefined, then
|
||||
if (first_day_of_week.has_value()) {
|
||||
// a. Set firstDay to !WeekdayToString(fw).
|
||||
first_day_string = MUST(String::from_utf8(weekday_to_string(*first_day_of_week)));
|
||||
}
|
||||
|
||||
// 22. Set opt.[[fw]] to firstDay.
|
||||
opt.fw = move(first_day_string);
|
||||
|
||||
// 23. Let hc be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined).
|
||||
// 24. Set opt.[[hc]] to hc.
|
||||
opt.hc = TRY(get_string_option(vm, *options, vm.names.hourCycle, nullptr, AK::Array { "h11"sv, "h12"sv, "h23"sv, "h24"sv }));
|
||||
|
||||
// 21. Let kf be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined).
|
||||
// 22. Set opt.[[kf]] to kf.
|
||||
// 25. Let kf be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined).
|
||||
// 26. Set opt.[[kf]] to kf.
|
||||
opt.kf = TRY(get_string_option(vm, *options, vm.names.caseFirst, nullptr, AK::Array { "upper"sv, "lower"sv, "false"sv }));
|
||||
|
||||
// 23. Let kn be ? GetOption(options, "numeric", boolean, empty, undefined).
|
||||
// 27. Let kn be ? GetOption(options, "numeric", boolean, empty, undefined).
|
||||
auto kn = TRY(get_option(vm, *options, vm.names.numeric, OptionType::Boolean, {}, Empty {}));
|
||||
|
||||
// 24. If kn is not undefined, set kn to ! ToString(kn).
|
||||
// 25. Set opt.[[kn]] to kn.
|
||||
// 28. If kn is not undefined, set kn to ! ToString(kn).
|
||||
// 29. Set opt.[[kn]] to kn.
|
||||
if (!kn.is_undefined())
|
||||
opt.kn = TRY(kn.to_string(vm));
|
||||
|
||||
// 26. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined).
|
||||
// 27. If numberingSystem is not undefined, then
|
||||
// 30. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined).
|
||||
// 31. If numberingSystem is not undefined, then
|
||||
// a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
|
||||
// 28. Set opt.[[nu]] to numberingSystem.
|
||||
// 32. Set opt.[[nu]] to numberingSystem.
|
||||
opt.nu = TRY(get_string_option(vm, *options, vm.names.numberingSystem, ::Locale::is_type_identifier));
|
||||
|
||||
// 29. Let r be ! ApplyUnicodeExtensionToTag(tag, opt, relevantExtensionKeys).
|
||||
// 33. Let r be ! ApplyUnicodeExtensionToTag(tag, opt, relevantExtensionKeys).
|
||||
auto result = apply_unicode_extension_to_tag(tag, move(opt), relevant_extension_keys);
|
||||
|
||||
// 30. Set locale.[[Locale]] to r.[[locale]].
|
||||
// 34. Set locale.[[Locale]] to r.[[locale]].
|
||||
locale->set_locale(move(result.locale));
|
||||
// 31. Set locale.[[Calendar]] to r.[[ca]].
|
||||
|
||||
// 35. Set locale.[[Calendar]] to r.[[ca]].
|
||||
if (result.ca.has_value())
|
||||
locale->set_calendar(result.ca.release_value());
|
||||
// 32. Set locale.[[Collation]] to r.[[co]].
|
||||
|
||||
// 36. Set locale.[[Collation]] to r.[[co]].
|
||||
if (result.co.has_value())
|
||||
locale->set_collation(result.co.release_value());
|
||||
// 33. Set locale.[[HourCycle]] to r.[[hc]].
|
||||
|
||||
// 37. Let firstDay be undefined.
|
||||
Optional<u8> first_day_numeric;
|
||||
|
||||
// 38. If r.[[fw]] is not undefined, then
|
||||
if (result.fw.has_value()) {
|
||||
// a. Set firstDay to ! WeekdayToNumber(r.[[fw]]).
|
||||
first_day_numeric = weekday_to_number(*result.fw);
|
||||
}
|
||||
|
||||
// 39. Set locale.[[FirstDayOfWeek]] to firstDay.
|
||||
if (first_day_numeric.has_value())
|
||||
locale->set_first_day_of_week(*first_day_numeric);
|
||||
|
||||
// 40. Set locale.[[HourCycle]] to r.[[hc]].
|
||||
if (result.hc.has_value())
|
||||
locale->set_hour_cycle(result.hc.release_value());
|
||||
|
||||
// 34. If relevantExtensionKeys contains "kf", then
|
||||
// 41. If relevantExtensionKeys contains "kf", then
|
||||
if (relevant_extension_keys.span().contains_slow("kf"sv)) {
|
||||
// a. Set locale.[[CaseFirst]] to r.[[kf]].
|
||||
if (result.kf.has_value())
|
||||
locale->set_case_first(result.kf.release_value());
|
||||
}
|
||||
|
||||
// 35. If relevantExtensionKeys contains "kn", then
|
||||
// 42. If relevantExtensionKeys contains "kn", then
|
||||
if (relevant_extension_keys.span().contains_slow("kn"sv)) {
|
||||
// a. If SameValue(r.[[kn]], "true") is true or r.[[kn]] is the empty String, then
|
||||
if (result.kn.has_value() && (result.kn == "true"sv || result.kn->is_empty())) {
|
||||
|
@ -357,11 +392,11 @@ ThrowCompletionOr<NonnullGCPtr<Object>> LocaleConstructor::construct(FunctionObj
|
|||
}
|
||||
}
|
||||
|
||||
// 36. Set locale.[[NumberingSystem]] to r.[[nu]].
|
||||
// 43. Set locale.[[NumberingSystem]] to r.[[nu]].
|
||||
if (result.nu.has_value())
|
||||
locale->set_numbering_system(result.nu.release_value());
|
||||
|
||||
// 37. Return locale.
|
||||
// 44. Return locale.
|
||||
return locale;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ void LocalePrototype::initialize(Realm& realm)
|
|||
define_native_accessor(realm, vm.names.caseFirst, case_first, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.collation, collation, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.collations, collations, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.firstDayOfWeek, first_day_of_week, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.hourCycle, hour_cycle, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.hourCycles, hour_cycles, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.numberingSystem, numbering_system, {}, Attribute::Configurable);
|
||||
|
@ -141,6 +142,17 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::base_name)
|
|||
JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
// 1.4.10 get Intl.Locale.prototype.firstDayOfWeek, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.firstDayOfWeek
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::first_day_of_week)
|
||||
{
|
||||
// 1. Let loc be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(loc, [[InitializedLocale]]).
|
||||
auto locale_object = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return loc.[[FirstDayOfWeek]].
|
||||
return locale_object->has_first_day_of_week() ? Value { locale_object->first_day_of_week() } : js_undefined();
|
||||
}
|
||||
|
||||
// 14.3.11 get Intl.Locale.prototype.numeric, https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numeric
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::numeric)
|
||||
{
|
||||
|
@ -217,10 +229,10 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
|
|||
__JS_ENUMERATE(hour_cycles) \
|
||||
__JS_ENUMERATE(numbering_systems)
|
||||
|
||||
// 1.4.16 get Intl.Locale.prototype.calendars, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.calendars
|
||||
// 1.4.17 get Intl.Locale.prototype.collations, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.collations
|
||||
// 1.4.18 get Intl.Locale.prototype.hourCycles, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.hourCycles
|
||||
// 1.4.19 get Intl.Locale.prototype.numberingSystems, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.numberingSystems
|
||||
// 1.4.17 get Intl.Locale.prototype.calendars, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.calendars
|
||||
// 1.4.18 get Intl.Locale.prototype.collations, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.collations
|
||||
// 1.4.19 get Intl.Locale.prototype.hourCycles, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.hourCycles
|
||||
// 1.4.20 get Intl.Locale.prototype.numberingSystems, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.numberingSystems
|
||||
#define __JS_ENUMERATE(keyword) \
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::keyword) \
|
||||
{ \
|
||||
|
@ -230,7 +242,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::region)
|
|||
JS_ENUMERATE_LOCALE_INFO_PROPERTIES
|
||||
#undef __JS_ENUMERATE
|
||||
|
||||
// 1.4.20 get Intl.Locale.prototype.timeZones, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.timeZones
|
||||
// 1.4.21 get Intl.Locale.prototype.timeZones, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.timeZones
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::time_zones)
|
||||
{
|
||||
// 1. Let loc be the this value.
|
||||
|
@ -248,7 +260,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::time_zones)
|
|||
return time_zones_of_locale(vm, locale->language_id.region.value());
|
||||
}
|
||||
|
||||
// 1.4.21 get Intl.Locale.prototype.textInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.textInfo
|
||||
// 1.4.22 get Intl.Locale.prototype.textInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.textInfo
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::text_info)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
@ -270,7 +282,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::text_info)
|
|||
return info;
|
||||
}
|
||||
|
||||
// 1.4.22 get Intl.Locale.prototype.weekInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.weekInfo
|
||||
// 1.4.23 get Intl.Locale.prototype.weekInfo, https://tc39.es/proposal-intl-locale-info/#sec-Intl.Locale.prototype.weekInfo
|
||||
JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::week_info)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
|
|
@ -31,6 +31,7 @@ private:
|
|||
JS_DECLARE_NATIVE_FUNCTION(case_first);
|
||||
JS_DECLARE_NATIVE_FUNCTION(collation);
|
||||
JS_DECLARE_NATIVE_FUNCTION(collations);
|
||||
JS_DECLARE_NATIVE_FUNCTION(first_day_of_week);
|
||||
JS_DECLARE_NATIVE_FUNCTION(hour_cycle);
|
||||
JS_DECLARE_NATIVE_FUNCTION(hour_cycles);
|
||||
JS_DECLARE_NATIVE_FUNCTION(numbering_system);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
describe("errors", () => {
|
||||
test("called on non-Locale object", () => {
|
||||
expect(() => {
|
||||
Intl.Locale.prototype.firstDayOfWeek;
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Intl.Locale");
|
||||
});
|
||||
|
||||
test("invalid options", () => {
|
||||
[100, Infinity, NaN, "hello", 152n, true].forEach(value => {
|
||||
expect(() => {
|
||||
new Intl.Locale("en", { firstDayOfWeek: value }).firstDayOfWeek;
|
||||
}).toThrowWithMessage(
|
||||
RangeError,
|
||||
`${value} is not a valid value for option firstDayOfWeek`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// FIXME: Spec issue: It is not yet clear if the following invalid values should throw. For now, this tests our
|
||||
// existing workaround behavior, which returns "undefined" for invalid extensions.
|
||||
// https://github.com/tc39/proposal-intl-locale-info/issues/78
|
||||
test("invalid extensions", () => {
|
||||
[100, Infinity, NaN, "hello", 152n, true].forEach(value => {
|
||||
expect(new Intl.Locale(`en-u-fw-${value}`).firstDayOfWeek).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("normal behavior", () => {
|
||||
test("valid options", () => {
|
||||
expect(new Intl.Locale("en").firstDayOfWeek).toBeUndefined();
|
||||
|
||||
["mon", "tue", "wed", "thu", "fri", "sat", "sun"].forEach((day, index) => {
|
||||
expect(new Intl.Locale(`en-u-fw-${day}`).firstDayOfWeek).toBe(index + 1);
|
||||
expect(new Intl.Locale("en", { firstDayOfWeek: day }).firstDayOfWeek).toBe(index + 1);
|
||||
expect(new Intl.Locale("en", { firstDayOfWeek: index + 1 }).firstDayOfWeek).toBe(
|
||||
index + 1
|
||||
);
|
||||
expect(new Intl.Locale("en-u-fw-mon", { firstDayOfWeek: day }).firstDayOfWeek).toBe(
|
||||
index + 1
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue