2021-09-08 21:34:27 -04:00
/*
2022-03-15 10:58:47 -04:00
* Copyright ( c ) 2021 - 2022 , Tim Flynn < trflynn89 @ serenityos . org >
2021-09-08 21:34:27 -04:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibJS/Runtime/AbstractOperations.h>
2021-09-10 11:12:05 -04:00
# include <LibJS/Runtime/Array.h>
2021-09-08 21:34:27 -04:00
# include <LibJS/Runtime/GlobalObject.h>
2021-09-10 11:04:54 -04:00
# include <LibJS/Runtime/Intl/AbstractOperations.h>
2021-09-08 21:34:27 -04:00
# include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
2022-03-15 10:58:47 -04:00
# include <LibUnicode/Locale.h>
2021-09-08 21:34:27 -04:00
namespace JS : : Intl {
2022-03-15 10:58:47 -04:00
// 15.1 The Intl.NumberFormat Constructor, https://tc39.es/ecma402/#sec-intl-numberformat-constructor
2021-09-08 21:34:27 -04:00
NumberFormatConstructor : : NumberFormatConstructor ( GlobalObject & global_object )
: NativeFunction ( vm ( ) . names . NumberFormat . as_string ( ) , * global_object . function_prototype ( ) )
{
}
void NumberFormatConstructor : : initialize ( GlobalObject & global_object )
{
NativeFunction : : initialize ( global_object ) ;
auto & vm = this - > vm ( ) ;
2022-03-15 10:58:47 -04:00
// 15.2.1 Intl.NumberFormat.prototype, https://tc39.es/ecma402/#sec-intl.numberformat.prototype
2021-09-08 21:34:27 -04:00
define_direct_property ( vm . names . prototype , global_object . intl_number_format_prototype ( ) , 0 ) ;
2021-09-10 11:12:05 -04:00
u8 attr = Attribute : : Writable | Attribute : : Configurable ;
2021-10-22 22:49:43 +01:00
define_native_function ( vm . names . supportedLocalesOf , supported_locales_of , 1 , attr ) ;
2021-09-10 11:12:05 -04:00
2021-09-08 21:34:27 -04:00
define_direct_property ( vm . names . length , Value ( 0 ) , Attribute : : Configurable ) ;
}
2022-03-15 10:58:47 -04:00
// 15.1.1 Intl.NumberFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.numberformat
2021-10-20 21:16:30 +01:00
ThrowCompletionOr < Value > NumberFormatConstructor : : call ( )
2021-09-08 21:34:27 -04:00
{
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
2021-10-20 21:16:30 +01:00
return TRY ( construct ( * this ) ) ;
2021-09-08 21:34:27 -04:00
}
2022-03-15 10:58:47 -04:00
// 15.1.1 Intl.NumberFormat ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.numberformat
2021-10-20 21:16:30 +01:00
ThrowCompletionOr < Object * > NumberFormatConstructor : : construct ( FunctionObject & new_target )
2021-09-08 21:34:27 -04:00
{
auto & vm = this - > vm ( ) ;
auto & global_object = this - > global_object ( ) ;
2021-09-10 11:04:54 -04:00
auto locales = vm . argument ( 0 ) ;
auto options = vm . argument ( 1 ) ;
2021-09-08 21:34:27 -04:00
// 2. Let numberFormat be ? OrdinaryCreateFromConstructor(newTarget, "%NumberFormat.prototype%", « [[InitializedNumberFormat]], [[Locale]], [[DataLocale]], [[NumberingSystem]], [[Style]], [[Unit]], [[UnitDisplay]], [[Currency]], [[CurrencyDisplay]], [[CurrencySign]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]], [[Notation]], [[CompactDisplay]], [[UseGrouping]], [[SignDisplay]], [[BoundFormat]] »).
2021-10-20 21:16:30 +01:00
auto * number_format = TRY ( ordinary_create_from_constructor < NumberFormat > ( global_object , new_target , & GlobalObject : : intl_number_format_prototype ) ) ;
2021-09-08 21:34:27 -04:00
2021-09-10 11:04:54 -04:00
// 3. Perform ? InitializeNumberFormat(numberFormat, locales, options).
2021-10-20 21:16:30 +01:00
TRY ( initialize_number_format ( global_object , * number_format , locales , options ) ) ;
2021-09-10 11:04:54 -04:00
// 4. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
// a. Let this be the this value.
// b. Return ? ChainNumberFormat(numberFormat, NewTarget, this).
2021-09-08 21:34:27 -04:00
// 5. Return numberFormat.
return number_format ;
}
2022-03-15 10:58:47 -04:00
// 15.2.2 Intl.NumberFormat.supportedLocalesOf ( locales [ , options ] ), https://tc39.es/ecma402/#sec-intl.numberformat.supportedlocalesof
2021-10-22 22:49:43 +01:00
JS_DEFINE_NATIVE_FUNCTION ( NumberFormatConstructor : : supported_locales_of )
2021-09-10 11:12:05 -04:00
{
auto locales = vm . argument ( 0 ) ;
auto options = vm . argument ( 1 ) ;
// 1. Let availableLocales be %NumberFormat%.[[AvailableLocales]].
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
2021-10-22 22:49:43 +01:00
auto requested_locales = TRY ( canonicalize_locale_list ( global_object , locales ) ) ;
2021-09-10 11:12:05 -04:00
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).
2021-10-22 22:49:43 +01:00
return TRY ( supported_locales ( global_object , requested_locales , options ) ) ;
2021-09-10 11:12:05 -04:00
}
2022-03-15 10:58:47 -04:00
// 15.1.2 InitializeNumberFormat ( numberFormat, locales, options ), https://tc39.es/ecma402/#sec-initializenumberformat
2022-07-12 13:18:23 -04:00
// 1.1.2 InitializeNumberFormat ( numberFormat, locales, options ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-initializenumberformat
2022-03-15 10:58:47 -04:00
ThrowCompletionOr < NumberFormat * > initialize_number_format ( GlobalObject & global_object , NumberFormat & number_format , Value locales_value , Value options_value )
{
auto & vm = global_object . vm ( ) ;
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
auto requested_locales = TRY ( canonicalize_locale_list ( global_object , locales_value ) ) ;
// 2. Set options to ? CoerceOptionsToObject(options).
auto * options = TRY ( coerce_options_to_object ( global_object , options_value ) ) ;
// 3. Let opt be a new Record.
LocaleOptions opt { } ;
// 4. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
2022-06-14 23:03:25 +01:00
auto matcher = TRY ( get_option ( global_object , * options , vm . names . localeMatcher , OptionType : : String , { " lookup " sv , " best fit " sv } , " best fit " sv ) ) ;
2022-03-15 10:58:47 -04:00
// 5. Set opt.[[localeMatcher]] to matcher.
opt . locale_matcher = matcher ;
// 6. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined).
2022-06-14 23:03:25 +01:00
auto numbering_system = TRY ( get_option ( global_object , * options , vm . names . numberingSystem , OptionType : : String , { } , Empty { } ) ) ;
2022-03-15 10:58:47 -04:00
// 7. If numberingSystem is not undefined, then
if ( ! numbering_system . is_undefined ( ) ) {
// a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
if ( ! Unicode : : is_type_identifier ( numbering_system . as_string ( ) . string ( ) ) )
return vm . throw_completion < RangeError > ( global_object , ErrorType : : OptionIsNotValidValue , numbering_system , " numberingSystem " sv ) ;
// 8. Set opt.[[nu]] to numberingSystem.
opt . nu = numbering_system . as_string ( ) . string ( ) ;
}
// 9. Let localeData be %NumberFormat%.[[LocaleData]].
// 10. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]], requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]], localeData).
auto result = resolve_locale ( requested_locales , opt , NumberFormat : : relevant_extension_keys ( ) ) ;
// 11. Set numberFormat.[[Locale]] to r.[[locale]].
number_format . set_locale ( move ( result . locale ) ) ;
// 12. Set numberFormat.[[DataLocale]] to r.[[dataLocale]].
number_format . set_data_locale ( move ( result . data_locale ) ) ;
// 13. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
if ( result . nu . has_value ( ) )
number_format . set_numbering_system ( result . nu . release_value ( ) ) ;
// 14. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
TRY ( set_number_format_unit_options ( global_object , number_format , * options ) ) ;
// 15. Let style be numberFormat.[[Style]].
auto style = number_format . style ( ) ;
int default_min_fraction_digits = 0 ;
int default_max_fraction_digits = 0 ;
// 16. If style is "currency", then
if ( style = = NumberFormat : : Style : : Currency ) {
// a. Let currency be numberFormat.[[Currency]].
auto const & currency = number_format . currency ( ) ;
// b. Let cDigits be CurrencyDigits(currency).
int digits = currency_digits ( currency ) ;
// c. Let mnfdDefault be cDigits.
default_min_fraction_digits = digits ;
// d. Let mxfdDefault be cDigits.
default_max_fraction_digits = digits ;
}
// 17. Else,
else {
// a. Let mnfdDefault be 0.
default_min_fraction_digits = 0 ;
// b. If style is "percent", then
// i. Let mxfdDefault be 0.
// c. Else,
// i. Let mxfdDefault be 3.
default_max_fraction_digits = style = = NumberFormat : : Style : : Percent ? 0 : 3 ;
}
// 18. Let notation be ? GetOption(options, "notation", "string", « "standard", "scientific", "engineering", "compact" », "standard").
2022-06-14 23:03:25 +01:00
auto notation = TRY ( get_option ( global_object , * options , vm . names . notation , OptionType : : String , { " standard " sv , " scientific " sv , " engineering " sv , " compact " sv } , " standard " sv ) ) ;
2022-03-15 10:58:47 -04:00
// 19. Set numberFormat.[[Notation]] to notation.
number_format . set_notation ( notation . as_string ( ) . string ( ) ) ;
// 20. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
TRY ( set_number_format_digit_options ( global_object , number_format , * options , default_min_fraction_digits , default_max_fraction_digits , number_format . notation ( ) ) ) ;
2022-07-12 13:18:23 -04:00
// 21. Let roundingIncrement be ? GetNumberOption(options, "roundingIncrement", 1, 5000, 1).
auto rounding_increment = TRY ( get_number_option ( global_object , * options , vm . names . roundingIncrement , 1 , 5000 , 1 ) ) ;
// 22. If roundingIncrement is not in « 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000 », throw a RangeError exception.
static constexpr auto sanctioned_rounding_increments = AK : : Array { 1 , 2 , 5 , 10 , 20 , 25 , 50 , 100 , 200 , 250 , 500 , 1000 , 2000 , 2500 , 5000 } ;
if ( ! sanctioned_rounding_increments . span ( ) . contains_slow ( * rounding_increment ) )
return vm . throw_completion < RangeError > ( global_object , ErrorType : : IntlInvalidRoundingIncrement , * rounding_increment ) ;
// 23. If roundingIncrement is not 1 and numberFormat.[[RoundingType]] is not fractionDigits, throw a TypeError exception.
if ( ( rounding_increment ! = 1 ) & & ( number_format . rounding_type ( ) ! = NumberFormatBase : : RoundingType : : FractionDigits ) )
return vm . throw_completion < TypeError > ( global_object , ErrorType : : IntlInvalidRoundingIncrementForRoundingType , * rounding_increment , number_format . rounding_type_string ( ) ) ;
// 24. If roundingIncrement is not 1 and numberFormat.[[MaximumFractionDigits]] is not equal to numberFormat.[[MinimumFractionDigits]], throw a RangeError exception.
if ( ( rounding_increment ! = 1 ) & & ( number_format . max_fraction_digits ( ) ! = number_format . min_fraction_digits ( ) ) )
return vm . throw_completion < RangeError > ( global_object , ErrorType : : IntlInvalidRoundingIncrementForFractionDigits , * rounding_increment ) ;
// 25. Set numberFormat.[[RoundingIncrement]] to roundingIncrement.
number_format . set_rounding_increment ( * rounding_increment ) ;
// 26. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", "string", « "auto", "stripIfInteger" », "auto").
auto trailing_zero_display = TRY ( get_option ( global_object , * options , vm . names . trailingZeroDisplay , OptionType : : String , { " auto " sv , " stripIfInteger " sv } , " auto " sv ) ) ;
// 27. Set numberFormat.[[TrailingZeroDisplay]] to trailingZeroDisplay.
number_format . set_trailing_zero_display ( trailing_zero_display . as_string ( ) . string ( ) ) ;
// 28. Let compactDisplay be ? GetOption(options, "compactDisplay", "string", « "short", "long" », "short").
2022-06-14 23:03:25 +01:00
auto compact_display = TRY ( get_option ( global_object , * options , vm . names . compactDisplay , OptionType : : String , { " short " sv , " long " sv } , " short " sv ) ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// 29. Let defaultUseGrouping be "auto".
auto default_use_grouping = " auto " sv ;
// 30. If notation is "compact", then
2022-03-15 10:58:47 -04:00
if ( number_format . notation ( ) = = NumberFormat : : Notation : : Compact ) {
// a. Set numberFormat.[[CompactDisplay]] to compactDisplay.
number_format . set_compact_display ( compact_display . as_string ( ) . string ( ) ) ;
2022-07-12 13:18:23 -04:00
// b. Set defaultUseGrouping to "min2".
default_use_grouping = " min2 " sv ;
2022-03-15 10:58:47 -04:00
}
2022-07-12 13:18:23 -04:00
// 31. Let useGrouping be ? GetStringOrBooleanOption(options, "useGrouping", « "min2", "auto", "always" », "always", false, defaultUseGrouping).
auto use_grouping = TRY ( get_string_or_boolean_option ( global_object , * options , vm . names . useGrouping , { " min2 " sv , " auto " sv , " always " sv } , " always " sv , false , default_use_grouping ) ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// 32. Set numberFormat.[[UseGrouping]] to useGrouping.
number_format . set_use_grouping ( use_grouping ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// 33. Let signDisplay be ? GetOption(options, "signDisplay", "string", « "auto", "never", "always", "exceptZero, "negative" », "auto").
auto sign_display = TRY ( get_option ( global_object , * options , vm . names . signDisplay , OptionType : : String , { " auto " sv , " never " sv , " always " sv , " exceptZero " sv , " negative " sv } , " auto " sv ) ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// 34. Set numberFormat.[[SignDisplay]] to signDisplay.
2022-03-15 10:58:47 -04:00
number_format . set_sign_display ( sign_display . as_string ( ) . string ( ) ) ;
2022-07-12 13:18:23 -04:00
// 35. Let roundingMode be ? GetOption(options, "roundingMode", "string", « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand").
auto rounding_mode = TRY ( get_option ( global_object , * options , vm . names . roundingMode , OptionType : : String , { " ceil " sv , " floor " sv , " expand " sv , " trunc " sv , " halfCeil " sv , " halfFloor " sv , " halfExpand " sv , " halfTrunc " sv , " halfEven " sv } , " halfExpand " sv ) ) ;
// 36. Set numberFormat.[[RoundingMode]] to roundingMode.
number_format . set_rounding_mode ( rounding_mode . as_string ( ) . string ( ) ) ;
// 37. Return numberFormat.
2022-03-15 10:58:47 -04:00
return & number_format ;
}
// 15.1.3 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation ), https://tc39.es/ecma402/#sec-setnfdigitoptions
2022-07-12 13:18:23 -04:00
// 1.1.1 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-setnfdigitoptions
2022-03-15 10:58:47 -04:00
ThrowCompletionOr < void > set_number_format_digit_options ( GlobalObject & global_object , NumberFormatBase & intl_object , Object const & options , int default_min_fraction_digits , int default_max_fraction_digits , NumberFormat : : Notation notation )
{
auto & vm = global_object . vm ( ) ;
// 1. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, 1).
auto min_integer_digits = TRY ( get_number_option ( global_object , options , vm . names . minimumIntegerDigits , 1 , 21 , 1 ) ) ;
// 2. Let mnfd be ? Get(options, "minimumFractionDigits").
auto min_fraction_digits = TRY ( options . get ( vm . names . minimumFractionDigits ) ) ;
// 3. Let mxfd be ? Get(options, "maximumFractionDigits").
auto max_fraction_digits = TRY ( options . get ( vm . names . maximumFractionDigits ) ) ;
// 4. Let mnsd be ? Get(options, "minimumSignificantDigits").
auto min_significant_digits = TRY ( options . get ( vm . names . minimumSignificantDigits ) ) ;
// 5. Let mxsd be ? Get(options, "maximumSignificantDigits").
auto max_significant_digits = TRY ( options . get ( vm . names . maximumSignificantDigits ) ) ;
// 6. Set intlObj.[[MinimumIntegerDigits]] to mnid.
intl_object . set_min_integer_digits ( * min_integer_digits ) ;
2022-07-12 13:18:23 -04:00
// 7. Let roundingPriority be ? GetOption(options, "roundingPriority", "string", « "auto", "morePrecision", "lessPrecision" », "auto").
auto rounding_priority = TRY ( get_option ( global_object , options , vm . names . roundingPriority , OptionType : : String , { " auto " sv , " morePrecision " sv , " lessPrecision " sv } , " auto " sv ) ) ;
// 8. If mnsd is not undefined or mxsd is not undefined, then
2022-03-15 10:58:47 -04:00
// a. Let hasSd be true.
2022-07-12 13:18:23 -04:00
// 9. Else,
2022-03-15 10:58:47 -04:00
// a. Let hasSd be false.
bool has_significant_digits = ! min_significant_digits . is_undefined ( ) | | ! max_significant_digits . is_undefined ( ) ;
2022-07-12 13:18:23 -04:00
// 10. If mnfd is not undefined or mxfd is not undefined, then
2022-03-15 10:58:47 -04:00
// a. Let hasFd be true.
2022-07-12 13:18:23 -04:00
// 11. Else,
2022-03-15 10:58:47 -04:00
// a. Let hasFd be false.
bool has_fraction_digits = ! min_fraction_digits . is_undefined ( ) | | ! max_fraction_digits . is_undefined ( ) ;
2022-07-12 13:18:23 -04:00
// 12. Let needSd be true.
bool need_significant_digits = true ;
// 13. Let needFd be true.
bool need_fraction_digits = true ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// 14. If roundingPriority is "auto", then
if ( rounding_priority . as_string ( ) . string ( ) = = " auto " sv ) {
// a. Set needSd to hasSd.
need_significant_digits = has_significant_digits ;
// b. If hasSd is true, or hasFd is false and notation is "compact", then
if ( has_significant_digits | | ( ! has_fraction_digits & & notation = = NumberFormat : : Notation : : Compact ) ) {
// i. Set needFd to false.
need_fraction_digits = false ;
}
}
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// 15. If needSd is true, then
2022-03-15 10:58:47 -04:00
if ( need_significant_digits ) {
2022-07-12 13:18:23 -04:00
// a. If hasSd is true, then
if ( has_significant_digits ) {
// i. Set mnsd to ? DefaultNumberOption(mnsd, 1, 21, 1).
auto min_digits = TRY ( default_number_option ( global_object , min_significant_digits , 1 , 21 , 1 ) ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// ii. Set mxsd to ? DefaultNumberOption(mxsd, mnsd, 21, 21).
auto max_digits = TRY ( default_number_option ( global_object , max_significant_digits , * min_digits , 21 , 21 ) ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// iii. Set intlObj.[[MinimumSignificantDigits]] to mnsd.
intl_object . set_min_significant_digits ( * min_digits ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// iv. Set intlObj.[[MaximumSignificantDigits]] to mxsd.
intl_object . set_max_significant_digits ( * max_digits ) ;
}
// b. Else,
else {
// i. Set intlObj.[[MinimumSignificantDigits]] to 1.
intl_object . set_min_significant_digits ( 1 ) ;
2022-03-15 10:58:47 -04:00
2022-07-12 13:18:23 -04:00
// ii. Set intlObj.[[MaximumSignificantDigits]] to 21.
intl_object . set_max_significant_digits ( 21 ) ;
}
2022-03-15 10:58:47 -04:00
}
2022-07-12 13:18:23 -04:00
// 16. If needFd is true, then
2022-03-15 10:58:47 -04:00
if ( need_fraction_digits ) {
// a. If hasFd is true, then
if ( has_fraction_digits ) {
// i. Set mnfd to ? DefaultNumberOption(mnfd, 0, 20, undefined).
auto min_digits = TRY ( default_number_option ( global_object , min_fraction_digits , 0 , 20 , { } ) ) ;
// ii. Set mxfd to ? DefaultNumberOption(mxfd, 0, 20, undefined).
auto max_digits = TRY ( default_number_option ( global_object , max_fraction_digits , 0 , 20 , { } ) ) ;
// iii. If mnfd is undefined, set mnfd to min(mnfdDefault, mxfd).
if ( ! min_digits . has_value ( ) )
min_digits = min ( default_min_fraction_digits , * max_digits ) ;
// iv. Else if mxfd is undefined, set mxfd to max(mxfdDefault, mnfd).
else if ( ! max_digits . has_value ( ) )
max_digits = max ( default_max_fraction_digits , * min_digits ) ;
// v. Else if mnfd is greater than mxfd, throw a RangeError exception.
else if ( * min_digits > * max_digits )
return vm . throw_completion < RangeError > ( global_object , ErrorType : : IntlMinimumExceedsMaximum , * min_digits , * max_digits ) ;
// vi. Set intlObj.[[MinimumFractionDigits]] to mnfd.
intl_object . set_min_fraction_digits ( * min_digits ) ;
// vii. Set intlObj.[[MaximumFractionDigits]] to mxfd.
intl_object . set_max_fraction_digits ( * max_digits ) ;
}
// b. Else,
else {
// i. Set intlObj.[[MinimumFractionDigits]] to mnfdDefault.
intl_object . set_min_fraction_digits ( default_min_fraction_digits ) ;
// ii. Set intlObj.[[MaximumFractionDigits]] to mxfdDefault.
intl_object . set_max_fraction_digits ( default_max_fraction_digits ) ;
}
}
2022-07-12 13:18:23 -04:00
// 17. If needSd is true or needFd is true, then
if ( need_significant_digits | | need_fraction_digits ) {
// a. If roundingPriority is "morePrecision", then
if ( rounding_priority . as_string ( ) . string ( ) = = " morePrecision " sv ) {
// i. Set intlObj.[[RoundingType]] to morePrecision.
intl_object . set_rounding_type ( NumberFormatBase : : RoundingType : : MorePrecision ) ;
}
// b. Else if roundingPriority is "lessPrecision", then
else if ( rounding_priority . as_string ( ) . string ( ) = = " lessPrecision " sv ) {
// i. Set intlObj.[[RoundingType]] to lessPrecision.
intl_object . set_rounding_type ( NumberFormatBase : : RoundingType : : LessPrecision ) ;
}
// c. Else if hasSd is true, then
else if ( has_significant_digits ) {
// i. Set intlObj.[[RoundingType]] to significantDigits.
intl_object . set_rounding_type ( NumberFormatBase : : RoundingType : : SignificantDigits ) ;
}
// d. Else,
else {
// i. Set intlObj.[[RoundingType]] to fractionDigits.
intl_object . set_rounding_type ( NumberFormatBase : : RoundingType : : FractionDigits ) ;
}
2022-03-15 10:58:47 -04:00
}
2022-07-12 13:18:23 -04:00
2022-03-15 10:58:47 -04:00
// 18. Else,
else {
2022-07-12 13:18:23 -04:00
// a. Set intlObj.[[RoundingType]] to morePrecision.
intl_object . set_rounding_type ( NumberFormatBase : : RoundingType : : MorePrecision ) ;
// b. Set intlObj.[[MinimumFractionDigits]] to 0.
intl_object . set_min_fraction_digits ( 0 ) ;
// c. Set intlObj.[[MaximumFractionDigits]] to 0.
intl_object . set_max_fraction_digits ( 0 ) ;
// d. Set intlObj.[[MinimumSignificantDigits]] to 1.
intl_object . set_min_significant_digits ( 1 ) ;
// e. Set intlObj.[[MaximumSignificantDigits]] to 2.
intl_object . set_max_significant_digits ( 2 ) ;
2022-03-15 10:58:47 -04:00
}
return { } ;
}
// 15.1.4 SetNumberFormatUnitOptions ( intlObj, options ), https://tc39.es/ecma402/#sec-setnumberformatunitoptions
ThrowCompletionOr < void > set_number_format_unit_options ( GlobalObject & global_object , NumberFormat & intl_object , Object const & options )
{
auto & vm = global_object . vm ( ) ;
// 1. Assert: Type(intlObj) is Object.
// 2. Assert: Type(options) is Object.
// 3. Let style be ? GetOption(options, "style", "string", « "decimal", "percent", "currency", "unit" », "decimal").
2022-06-14 23:03:25 +01:00
auto style = TRY ( get_option ( global_object , options , vm . names . style , OptionType : : String , { " decimal " sv , " percent " sv , " currency " sv , " unit " sv } , " decimal " sv ) ) ;
2022-03-15 10:58:47 -04:00
// 4. Set intlObj.[[Style]] to style.
intl_object . set_style ( style . as_string ( ) . string ( ) ) ;
// 5. Let currency be ? GetOption(options, "currency", "string", undefined, undefined).
2022-06-14 23:03:25 +01:00
auto currency = TRY ( get_option ( global_object , options , vm . names . currency , OptionType : : String , { } , Empty { } ) ) ;
2022-03-15 10:58:47 -04:00
// 6. If currency is undefined, then
if ( currency . is_undefined ( ) ) {
// a. If style is "currency", throw a TypeError exception.
if ( intl_object . style ( ) = = NumberFormat : : Style : : Currency )
return vm . throw_completion < TypeError > ( global_object , ErrorType : : IntlOptionUndefined , " currency " sv , " style " sv , style ) ;
}
// 7. Else,
2022-03-28 09:53:06 -04:00
// a. If ! IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
2022-03-15 10:58:47 -04:00
else if ( ! is_well_formed_currency_code ( currency . as_string ( ) . string ( ) ) )
return vm . throw_completion < RangeError > ( global_object , ErrorType : : OptionIsNotValidValue , currency , " currency " sv ) ;
// 8. Let currencyDisplay be ? GetOption(options, "currencyDisplay", "string", « "code", "symbol", "narrowSymbol", "name" », "symbol").
2022-06-14 23:03:25 +01:00
auto currency_display = TRY ( get_option ( global_object , options , vm . names . currencyDisplay , OptionType : : String , { " code " sv , " symbol " sv , " narrowSymbol " sv , " name " sv } , " symbol " sv ) ) ;
2022-03-15 10:58:47 -04:00
// 9. Let currencySign be ? GetOption(options, "currencySign", "string", « "standard", "accounting" », "standard").
2022-06-14 23:03:25 +01:00
auto currency_sign = TRY ( get_option ( global_object , options , vm . names . currencySign , OptionType : : String , { " standard " sv , " accounting " sv } , " standard " sv ) ) ;
2022-03-15 10:58:47 -04:00
// 10. Let unit be ? GetOption(options, "unit", "string", undefined, undefined).
2022-06-14 23:03:25 +01:00
auto unit = TRY ( get_option ( global_object , options , vm . names . unit , OptionType : : String , { } , Empty { } ) ) ;
2022-03-15 10:58:47 -04:00
// 11. If unit is undefined, then
if ( unit . is_undefined ( ) ) {
// a. If style is "unit", throw a TypeError exception.
if ( intl_object . style ( ) = = NumberFormat : : Style : : Unit )
return vm . throw_completion < TypeError > ( global_object , ErrorType : : IntlOptionUndefined , " unit " sv , " style " sv , style ) ;
}
// 12. Else,
2022-03-28 09:53:06 -04:00
// a. If ! IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
2022-03-15 10:58:47 -04:00
else if ( ! is_well_formed_unit_identifier ( unit . as_string ( ) . string ( ) ) )
return vm . throw_completion < RangeError > ( global_object , ErrorType : : OptionIsNotValidValue , unit , " unit " sv ) ;
// 13. Let unitDisplay be ? GetOption(options, "unitDisplay", "string", « "short", "narrow", "long" », "short").
2022-06-14 23:03:25 +01:00
auto unit_display = TRY ( get_option ( global_object , options , vm . names . unitDisplay , OptionType : : String , { " short " sv , " narrow " sv , " long " sv } , " short " sv ) ) ;
2022-03-15 10:58:47 -04:00
// 14. If style is "currency", then
if ( intl_object . style ( ) = = NumberFormat : : Style : : Currency ) {
2022-03-28 09:53:06 -04:00
// a. Set intlObj.[[Currency]] to the ASCII-uppercase of currency.
2022-03-15 10:58:47 -04:00
intl_object . set_currency ( currency . as_string ( ) . string ( ) . to_uppercase ( ) ) ;
// c. Set intlObj.[[CurrencyDisplay]] to currencyDisplay.
intl_object . set_currency_display ( currency_display . as_string ( ) . string ( ) ) ;
// d. Set intlObj.[[CurrencySign]] to currencySign.
intl_object . set_currency_sign ( currency_sign . as_string ( ) . string ( ) ) ;
}
// 15. If style is "unit", then
if ( intl_object . style ( ) = = NumberFormat : : Style : : Unit ) {
// a. Set intlObj.[[Unit]] to unit.
intl_object . set_unit ( unit . as_string ( ) . string ( ) ) ;
// b. Set intlObj.[[UnitDisplay]] to unitDisplay.
intl_object . set_unit_display ( unit_display . as_string ( ) . string ( ) ) ;
}
return { } ;
}
2021-09-08 21:34:27 -04:00
}