2021-08-24 22:27:05 -04:00
/*
2022-01-31 13:07:22 -05:00
* Copyright ( c ) 2021 - 2022 , Tim Flynn < trflynn89 @ serenityos . org >
2021-08-24 22:27:05 -04:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibJS/Runtime/GlobalObject.h>
2021-09-11 07:50:54 -04:00
# include <LibJS/Runtime/Intl/AbstractOperations.h>
2021-08-24 22:27:05 -04:00
# include <LibJS/Runtime/Intl/DisplayNames.h>
namespace JS : : Intl {
// 12 DisplayNames Objects, https://tc39.es/ecma402/#intl-displaynames-objects
DisplayNames : : DisplayNames ( Object & prototype )
: Object ( prototype )
{
}
void DisplayNames : : set_type ( StringView type )
{
2022-01-12 13:44:55 -05:00
if ( type = = " language " sv )
2021-08-24 22:27:05 -04:00
m_type = Type : : Language ;
2022-01-12 13:44:55 -05:00
else if ( type = = " region " sv )
2021-08-24 22:27:05 -04:00
m_type = Type : : Region ;
2022-01-12 13:44:55 -05:00
else if ( type = = " script " sv )
2021-08-24 22:27:05 -04:00
m_type = Type : : Script ;
2022-01-12 13:44:55 -05:00
else if ( type = = " currency " sv )
2021-08-24 22:27:05 -04:00
m_type = Type : : Currency ;
2022-01-12 13:52:51 -05:00
else if ( type = = " calendar " sv )
m_type = Type : : Calendar ;
else if ( type = = " dateTimeField " sv )
m_type = Type : : DateTimeField ;
2022-01-12 13:44:55 -05:00
else
2021-08-24 22:27:05 -04:00
VERIFY_NOT_REACHED ( ) ;
}
StringView DisplayNames : : type_string ( ) const
{
switch ( m_type ) {
case Type : : Language :
return " language " sv ;
case Type : : Region :
return " region " sv ;
case Type : : Script :
return " script " sv ;
case Type : : Currency :
return " currency " sv ;
2022-01-12 13:52:51 -05:00
case Type : : Calendar :
return " calendar " sv ;
case Type : : DateTimeField :
return " dateTimeField " sv ;
2021-08-24 22:27:05 -04:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
void DisplayNames : : set_fallback ( StringView fallback )
{
2022-01-12 13:44:55 -05:00
if ( fallback = = " none " sv )
2021-08-24 22:27:05 -04:00
m_fallback = Fallback : : None ;
2022-01-12 13:44:55 -05:00
else if ( fallback = = " code " sv )
2021-08-24 22:27:05 -04:00
m_fallback = Fallback : : Code ;
2022-01-12 13:44:55 -05:00
else
2021-08-24 22:27:05 -04:00
VERIFY_NOT_REACHED ( ) ;
}
StringView DisplayNames : : fallback_string ( ) const
{
switch ( m_fallback ) {
case Fallback : : None :
return " none " sv ;
case Fallback : : Code :
return " code " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2022-01-12 13:52:51 -05:00
void DisplayNames : : set_language_display ( StringView language_display )
{
if ( language_display = = " dialect " sv )
m_language_display = LanguageDisplay : : Dialect ;
else if ( language_display = = " standard " sv )
m_language_display = LanguageDisplay : : Standard ;
else
VERIFY_NOT_REACHED ( ) ;
}
StringView DisplayNames : : language_display_string ( ) const
{
VERIFY ( m_language_display . has_value ( ) ) ;
switch ( * m_language_display ) {
case LanguageDisplay : : Dialect :
return " dialect " sv ;
case LanguageDisplay : : Standard :
return " standard " sv ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2022-03-15 10:40:51 -04:00
// 12.5.1 CanonicalCodeForDisplayNames ( type, code ), https://tc39.es/ecma402/#sec-canonicalcodefordisplaynames
2021-09-18 19:41:25 +03:00
ThrowCompletionOr < Value > canonical_code_for_display_names ( GlobalObject & global_object , DisplayNames : : Type type , StringView code )
2021-09-11 07:50:54 -04:00
{
auto & vm = global_object . vm ( ) ;
// 1. If type is "language", then
if ( type = = DisplayNames : : Type : : Language ) {
// a. If code does not match the unicode_language_id production, throw a RangeError exception.
2021-09-18 19:41:25 +03:00
if ( ! Unicode : : parse_unicode_language_id ( code ) . has_value ( ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " language " sv ) ;
2021-09-11 07:50:54 -04:00
// b. If IsStructurallyValidLanguageTag(code) is false, throw a RangeError exception.
auto locale_id = is_structurally_valid_language_tag ( code ) ;
2021-09-18 19:41:25 +03:00
if ( ! locale_id . has_value ( ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : IntlInvalidLanguageTag , code ) ;
2021-09-11 07:50:54 -04:00
2022-03-28 09:53:06 -04:00
// c. Return ! CanonicalizeUnicodeLocaleId(code).
2022-04-03 15:19:33 +01:00
auto canonicalized_tag = Intl : : canonicalize_unicode_locale_id ( * locale_id ) ;
2021-10-20 19:17:45 +01:00
return js_string ( vm , move ( canonicalized_tag ) ) ;
2021-09-11 07:50:54 -04:00
}
// 2. If type is "region", then
if ( type = = DisplayNames : : Type : : Region ) {
// a. If code does not match the unicode_region_subtag production, throw a RangeError exception.
2021-09-18 19:41:25 +03:00
if ( ! Unicode : : is_unicode_region_subtag ( code ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " region " sv ) ;
2021-09-11 07:50:54 -04:00
2022-03-28 09:53:06 -04:00
// b. Return the ASCII-uppercase of code.
2021-10-20 19:17:45 +01:00
return js_string ( vm , code . to_uppercase_string ( ) ) ;
2021-09-11 07:50:54 -04:00
}
// 3. If type is "script", then
if ( type = = DisplayNames : : Type : : Script ) {
// a. If code does not match the unicode_script_subtag production, throw a RangeError exception.
2021-09-18 19:41:25 +03:00
if ( ! Unicode : : is_unicode_script_subtag ( code ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " script " sv ) ;
2021-09-11 07:50:54 -04:00
2022-03-28 09:53:06 -04:00
// Assert: The length of code is 4, and every code unit of code represents an ASCII letter (0x0041 through 0x005A and 0x0061 through 0x007A, both inclusive).
VERIFY ( code . length ( ) = = 4 ) ;
VERIFY ( all_of ( code , is_ascii_alpha ) ) ;
// c. Let first be the ASCII-uppercase of the substring of code from 0 to 1.
// d. Let rest be the ASCII-lowercase of the substring of code from 1.
// e. Return the string-concatenation of first and rest.
2021-10-20 19:17:45 +01:00
return js_string ( vm , code . to_titlecase_string ( ) ) ;
2021-09-11 07:50:54 -04:00
}
2022-01-12 17:55:45 -05:00
// 4. If type is "calendar", then
if ( type = = DisplayNames : : Type : : Calendar ) {
// a. If code does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
if ( ! Unicode : : is_type_identifier ( code ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " calendar " sv ) ;
2022-01-12 17:55:45 -05:00
2022-03-28 08:48:18 -04:00
// b. If code uses any of the backwards compatibility syntax described in Unicode Technical Standard #35 LDML § 3.3 BCP 47 Conformance, throw a RangeError exception.
if ( code . contains ( ' _ ' ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " calendar " sv ) ;
2022-03-28 08:48:18 -04:00
2022-03-28 09:53:06 -04:00
// c. Return the ASCII-lowercase of code.
2022-01-12 17:55:45 -05:00
return js_string ( vm , code . to_lowercase_string ( ) ) ;
}
// 5. If type is "dateTimeField", then
if ( type = = DisplayNames : : Type : : DateTimeField ) {
// a. If the result of IsValidDateTimeFieldCode(code) is false, throw a RangeError exception.
if ( ! is_valid_date_time_field_code ( code ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " dateTimeField " sv ) ;
2022-01-12 17:55:45 -05:00
// b. Return code.
return js_string ( vm , code ) ;
}
// 6. Assert: type is "currency".
2021-09-11 07:50:54 -04:00
VERIFY ( type = = DisplayNames : : Type : : Currency ) ;
2022-01-12 17:55:45 -05:00
// 7. If ! IsWellFormedCurrencyCode(code) is false, throw a RangeError exception.
2021-09-18 19:41:25 +03:00
if ( ! is_well_formed_currency_code ( code ) )
2022-08-16 20:33:17 +01:00
return vm . throw_completion < RangeError > ( ErrorType : : OptionIsNotValidValue , code , " currency " sv ) ;
2021-09-11 07:50:54 -04:00
2022-03-28 09:53:06 -04:00
// 8. Return the ASCII-uppercase of code.
2021-10-20 19:17:45 +01:00
return js_string ( vm , code . to_uppercase_string ( ) ) ;
2021-09-11 07:50:54 -04:00
}
2022-03-15 10:40:51 -04:00
// 12.5.2 IsValidDateTimeFieldCode ( field ), https://tc39.es/ecma402/#sec-isvaliddatetimefieldcode
2022-01-12 17:55:45 -05:00
bool is_valid_date_time_field_code ( StringView field )
{
2022-03-15 10:40:51 -04:00
// 1. If field is listed in the Code column of Table 9, return true.
2022-01-12 17:55:45 -05:00
// 2. Return false.
return field . is_one_of ( " era " sv , " year " sv , " quarter " sv , " month " sv , " weekOfYear " sv , " weekday " sv , " day " sv , " dayPeriod " sv , " hour " sv , " minute " sv , " second " sv , " timeZoneName " sv ) ;
}
2021-08-24 22:27:05 -04:00
}