summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h2
-rw-r--r--Userland/Libraries/LibJS/Runtime/ErrorTypes.h3
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp33
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h9
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp123
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h69
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp174
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormatPrototype.cpp25
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.js122
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.resolvedOptions.js88
-rw-r--r--Userland/Utilities/js.cpp8
11 files changed, 585 insertions, 71 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
index 3f31a1bef4..fa43ef2a49 100644
--- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
+++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h
@@ -402,6 +402,7 @@ namespace JS {
P(round) \
P(roundingIncrement) \
P(roundingMode) \
+ P(roundingPriority) \
P(script) \
P(seal) \
P(second) \
@@ -514,6 +515,7 @@ namespace JS {
P(toZonedDateTime) \
P(toZonedDateTimeISO) \
P(trace) \
+ P(trailingZeroDisplay) \
P(trim) \
P(trimEnd) \
P(trimLeft) \
diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
index 0cf24d2edb..4bf8692948 100644
--- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
+++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h
@@ -43,6 +43,9 @@
M(IntlInvalidDateTimeFormatOption, "Option {} cannot be set when also providing {}") \
M(IntlInvalidKey, "{} is not a valid key") \
M(IntlInvalidLanguageTag, "{} is not a structurally valid language tag") \
+ M(IntlInvalidRoundingIncrement, "{} is not a valid rounding increment") \
+ M(IntlInvalidRoundingIncrementForFractionDigits, "{} is not a valid rounding increment for inequal min/max fraction digits") \
+ M(IntlInvalidRoundingIncrementForRoundingType, "{} is not a valid rounding increment for rounding type {}") \
M(IntlInvalidTime, "Time value must be between -8.64E15 and 8.64E15") \
M(IntlInvalidUnit, "Unit {} is not a valid time unit") \
M(IntlStartRangeAfterEndRange, "Range start {} is greater than range end {}") \
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp
index 403a774493..b22bf44c7c 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.cpp
@@ -605,6 +605,39 @@ ThrowCompletionOr<Object*> coerce_options_to_object(GlobalObject& global_object,
// NOTE: 9.2.13 GetOption has been removed and is being pulled in from ECMA-262 in the Temporal proposal.
+// 1.2.12 GetStringOrBooleanOption ( options, property, values, trueValue, falsyValue, fallback ), https://tc39.es/proposal-intl-numberformat-v3/out/negotiation/proposed.html#sec-getstringorbooleanoption
+ThrowCompletionOr<StringOrBoolean> get_string_or_boolean_option(GlobalObject& global_object, Object const& options, PropertyKey const& property, Span<StringView const> values, StringOrBoolean true_value, StringOrBoolean falsy_value, StringOrBoolean fallback)
+{
+ // 1. Let value be ? Get(options, property).
+ auto value = TRY(options.get(property));
+
+ // 2. If value is undefined, return fallback.
+ if (value.is_undefined())
+ return fallback;
+
+ // 3. If value is true, return trueValue.
+ if (value.is_boolean() && value.as_bool())
+ return true_value;
+
+ // 4. Let valueBoolean be ToBoolean(value).
+ auto value_boolean = value.to_boolean();
+
+ // 5. If valueBoolean is false, return falsyValue.
+ if (!value_boolean)
+ return falsy_value;
+
+ // 6. Let value be ? ToString(value).
+ auto value_string = TRY(value.to_string(global_object));
+
+ // 7. If values does not contain an element equal to value, return fallback.
+ auto it = find(values.begin(), values.end(), value_string);
+ if (it == values.end())
+ return fallback;
+
+ // 8. Return value.
+ return StringOrBoolean { *it };
+}
+
// 9.2.14 DefaultNumberOption ( value, minimum, maximum, fallback ), https://tc39.es/ecma402/#sec-defaultnumberoption
ThrowCompletionOr<Optional<int>> default_number_option(GlobalObject& global_object, Value value, int minimum, int maximum, Optional<int> fallback)
{
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h
index 561d909aef..93122774b2 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h
+++ b/Userland/Libraries/LibJS/Runtime/Intl/AbstractOperations.h
@@ -65,6 +65,8 @@ constexpr auto extra_sanctioned_single_unit_identifiers()
return AK::Array { "microsecond"sv, "nanosecond"sv };
}
+using StringOrBoolean = Variant<StringView, bool>;
+
Optional<Unicode::LocaleID> is_structurally_valid_language_tag(StringView locale);
String canonicalize_unicode_locale_id(Unicode::LocaleID& locale);
bool is_well_formed_currency_code(StringView currency);
@@ -77,10 +79,17 @@ Vector<String> lookup_supported_locales(Vector<String> const& requested_locales)
Vector<String> best_fit_supported_locales(Vector<String> const& requested_locales);
ThrowCompletionOr<Array*> supported_locales(GlobalObject&, Vector<String> const& requested_locales, Value options);
ThrowCompletionOr<Object*> coerce_options_to_object(GlobalObject& global_object, Value options);
+ThrowCompletionOr<StringOrBoolean> get_string_or_boolean_option(GlobalObject& global_object, Object const& options, PropertyKey const& property, Span<StringView const> values, StringOrBoolean true_value, StringOrBoolean falsy_value, StringOrBoolean fallback);
ThrowCompletionOr<Optional<int>> default_number_option(GlobalObject& global_object, Value value, int minimum, int maximum, Optional<int> fallback);
ThrowCompletionOr<Optional<int>> get_number_option(GlobalObject& global_object, Object const& options, PropertyKey const& property, int minimum, int maximum, Optional<int> fallback);
Vector<PatternPartition> partition_pattern(StringView pattern);
+template<size_t Size>
+ThrowCompletionOr<StringOrBoolean> get_string_or_boolean_option(GlobalObject& global_object, Object const& options, PropertyKey const& property, StringView const (&values)[Size], StringOrBoolean true_value, StringOrBoolean falsy_value, StringOrBoolean fallback)
+{
+ return get_string_or_boolean_option(global_object, options, property, Span<StringView const> { values }, move(true_value), move(falsy_value), move(fallback));
+}
+
// NOTE: ECMA-402's GetOption is being removed in favor of a shared ECMA-262 GetOption in the Temporal proposal.
// Until Temporal is merged into ECMA-262, our implementation lives in the Temporal-specific AO file & namespace.
using Temporal::get_option;
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp
index 6863ce6b34..bbf38d3ea3 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp
@@ -161,11 +161,122 @@ StringView NumberFormatBase::rounding_type_string() const
return "fractionDigits"sv;
case RoundingType::CompactRounding:
return "compactRounding"sv;
+ case RoundingType::MorePrecision:
+ return "morePrecision"sv;
+ case RoundingType::LessPrecision:
+ return "lessPrecision"sv;
default:
VERIFY_NOT_REACHED();
}
}
+StringView NumberFormatBase::rounding_mode_string() const
+{
+ switch (m_rounding_mode) {
+ case RoundingMode::Ceil:
+ return "ceil"sv;
+ case RoundingMode::Expand:
+ return "expand"sv;
+ case RoundingMode::Floor:
+ return "floor"sv;
+ case RoundingMode::HalfCeil:
+ return "halfCeil"sv;
+ case RoundingMode::HalfEven:
+ return "halfEven"sv;
+ case RoundingMode::HalfExpand:
+ return "halfExpand"sv;
+ case RoundingMode::HalfFloor:
+ return "halfFloor"sv;
+ case RoundingMode::HalfTrunc:
+ return "halfTrunc"sv;
+ case RoundingMode::Trunc:
+ return "trunc"sv;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+void NumberFormatBase::set_rounding_mode(StringView rounding_mode)
+{
+ if (rounding_mode == "ceil"sv)
+ m_rounding_mode = RoundingMode::Ceil;
+ else if (rounding_mode == "expand"sv)
+ m_rounding_mode = RoundingMode::Expand;
+ else if (rounding_mode == "floor"sv)
+ m_rounding_mode = RoundingMode::Floor;
+ else if (rounding_mode == "halfCeil"sv)
+ m_rounding_mode = RoundingMode::HalfCeil;
+ else if (rounding_mode == "halfEven"sv)
+ m_rounding_mode = RoundingMode::HalfEven;
+ else if (rounding_mode == "halfExpand"sv)
+ m_rounding_mode = RoundingMode::HalfExpand;
+ else if (rounding_mode == "halfFloor"sv)
+ m_rounding_mode = RoundingMode::HalfFloor;
+ else if (rounding_mode == "halfTrunc"sv)
+ m_rounding_mode = RoundingMode::HalfTrunc;
+ else if (rounding_mode == "trunc"sv)
+ m_rounding_mode = RoundingMode::Trunc;
+}
+
+StringView NumberFormatBase::trailing_zero_display_string() const
+{
+ switch (m_trailing_zero_display) {
+ case TrailingZeroDisplay::Auto:
+ return "auto"sv;
+ case TrailingZeroDisplay::StripIfInteger:
+ return "stripIfInteger"sv;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+void NumberFormatBase::set_trailing_zero_display(StringView trailing_zero_display)
+{
+ if (trailing_zero_display == "auto"sv)
+ m_trailing_zero_display = TrailingZeroDisplay::Auto;
+ else if (trailing_zero_display == "stripIfInteger"sv)
+ m_trailing_zero_display = TrailingZeroDisplay::StripIfInteger;
+ else
+ VERIFY_NOT_REACHED();
+}
+
+Value NumberFormat::use_grouping_to_value(GlobalObject& global_object) const
+{
+ auto& vm = global_object.vm();
+
+ switch (m_use_grouping) {
+ case UseGrouping::Always:
+ return js_string(vm, "always"sv);
+ case UseGrouping::Auto:
+ return js_string(vm, "auto"sv);
+ case UseGrouping::Min2:
+ return js_string(vm, "min2"sv);
+ case UseGrouping::False:
+ return Value(false);
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+void NumberFormat::set_use_grouping(StringOrBoolean const& use_grouping)
+{
+ use_grouping.visit(
+ [this](StringView grouping) {
+ if (grouping == "always"sv)
+ m_use_grouping = UseGrouping::Always;
+ else if (grouping == "auto"sv)
+ m_use_grouping = UseGrouping::Auto;
+ else if (grouping == "min2"sv)
+ m_use_grouping = UseGrouping::Min2;
+ else
+ VERIFY_NOT_REACHED();
+ },
+ [this](bool grouping) {
+ VERIFY(!grouping);
+ m_use_grouping = UseGrouping::False;
+ });
+}
+
void NumberFormat::set_notation(StringView notation)
{
if (notation == "standard"sv)
@@ -230,6 +341,8 @@ void NumberFormat::set_sign_display(StringView sign_display)
m_sign_display = SignDisplay::Always;
else if (sign_display == "exceptZero"sv)
m_sign_display = SignDisplay::ExceptZero;
+ else if (sign_display == "negative"sv)
+ m_sign_display = SignDisplay::Negative;
else
VERIFY_NOT_REACHED();
}
@@ -245,6 +358,8 @@ StringView NumberFormat::sign_display_string() const
return "always"sv;
case SignDisplay::ExceptZero:
return "exceptZero"sv;
+ case SignDisplay::Negative:
+ return "negative"sv;
default:
VERIFY_NOT_REACHED();
}
@@ -372,6 +487,8 @@ FormatResult format_numeric_to_string(GlobalObject& global_object, NumberFormatB
break;
// 5. Else,
+ case NumberFormatBase::RoundingType::MorePrecision: // FIXME: Handle this case for NumberFormat V3.
+ case NumberFormatBase::RoundingType::LessPrecision: // FIXME: Handle this case for NumberFormat V3.
case NumberFormatBase::RoundingType::CompactRounding:
// a. Assert: intlObject.[[RoundingType]] is compactRounding.
// b. Let result be ToRawPrecision(x, 1, 2).
@@ -662,7 +779,8 @@ Vector<PatternPartition> partition_notation_sub_pattern(GlobalObject& global_obj
// b. Let fraction be undefined.
}
- bool use_grouping = number_format.use_grouping();
+ // FIXME: Handle all NumberFormat V3 [[UseGrouping]] options.
+ bool use_grouping = number_format.use_grouping() != NumberFormat::UseGrouping::False;
// FIXME: The spec doesn't indicate this, but grouping should be disabled for numbers less than 10,000 when the notation is compact.
// This is addressed in Intl.NumberFormat V3 with the "min2" [[UseGrouping]] option. However, test262 explicitly expects this
@@ -1174,7 +1292,8 @@ Optional<Variant<StringView, String>> get_number_format_pattern(GlobalObject& gl
break;
default:
- VERIFY_NOT_REACHED();
+ // FIXME: Handle all NumberFormat V3 [[SignDisplay]] options.
+ return {};
}
found_pattern = patterns.release_value();
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h
index 1f08fe8ae5..56caf70875 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h
+++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.h
@@ -24,7 +24,28 @@ public:
Invalid,
SignificantDigits,
FractionDigits,
- CompactRounding,
+ CompactRounding, // FIXME: Remove this when corresponding AOs are updated for NumberFormat V3.
+ MorePrecision,
+ LessPrecision,
+ };
+
+ enum class RoundingMode {
+ Invalid,
+ Ceil,
+ Expand,
+ Floor,
+ HalfCeil,
+ HalfEven,
+ HalfExpand,
+ HalfFloor,
+ HalfTrunc,
+ Trunc,
+ };
+
+ enum class TrailingZeroDisplay {
+ Invalid,
+ Auto,
+ StripIfInteger,
};
NumberFormatBase(Object& prototype);
@@ -59,15 +80,29 @@ public:
StringView rounding_type_string() const;
void set_rounding_type(RoundingType rounding_type) { m_rounding_type = rounding_type; }
+ RoundingMode rounding_mode() const { return m_rounding_mode; }
+ StringView rounding_mode_string() const;
+ void set_rounding_mode(StringView rounding_mode);
+
+ int rounding_increment() const { return m_rounding_increment; }
+ void set_rounding_increment(int rounding_increment) { m_rounding_increment = rounding_increment; }
+
+ TrailingZeroDisplay trailing_zero_display() const { return m_trailing_zero_display; }
+ StringView trailing_zero_display_string() const;
+ void set_trailing_zero_display(StringView trailing_zero_display);
+
private:
- String m_locale; // [[Locale]]
- String m_data_locale; // [[DataLocale]]
- int m_min_integer_digits { 0 }; // [[MinimumIntegerDigits]]
- Optional<int> m_min_fraction_digits {}; // [[MinimumFractionDigits]]
- Optional<int> m_max_fraction_digits {}; // [[MaximumFractionDigits]]
- Optional<int> m_min_significant_digits {}; // [[MinimumSignificantDigits]]
- Optional<int> m_max_significant_digits {}; // [[MaximumSignificantDigits]]
- RoundingType m_rounding_type { RoundingType::Invalid }; // [[RoundingType]]
+ String m_locale; // [[Locale]]
+ String m_data_locale; // [[DataLocale]]
+ int m_min_integer_digits { 0 }; // [[MinimumIntegerDigits]]
+ Optional<int> m_min_fraction_digits {}; // [[MinimumFractionDigits]]
+ Optional<int> m_max_fraction_digits {}; // [[MaximumFractionDigits]]
+ Optional<int> m_min_significant_digits {}; // [[MinimumSignificantDigits]]
+ Optional<int> m_max_significant_digits {}; // [[MaximumSignificantDigits]]
+ RoundingType m_rounding_type { RoundingType::Invalid }; // [[RoundingType]]
+ RoundingMode m_rounding_mode { RoundingMode::Invalid }; // [[RoundingMode]]
+ int m_rounding_increment { 1 }; // [[RoundingIncrement]]
+ TrailingZeroDisplay m_trailing_zero_display { TrailingZeroDisplay::Invalid }; // [[TrailingZeroDisplay]]
};
class NumberFormat final : public NumberFormatBase {
@@ -120,6 +155,15 @@ public:
Never,
Always,
ExceptZero,
+ Negative,
+ };
+
+ enum class UseGrouping {
+ Invalid,
+ Always,
+ Auto,
+ Min2,
+ False,
};
static constexpr auto relevant_extension_keys()
@@ -163,8 +207,9 @@ public:
StringView unit_display_string() const { return Unicode::style_to_string(*m_unit_display); }
void set_unit_display(StringView unit_display) { m_unit_display = Unicode::style_from_string(unit_display); }
- bool use_grouping() const { return m_use_grouping; }
- void set_use_grouping(bool use_grouping) { m_use_grouping = use_grouping; }
+ UseGrouping use_grouping() const { return m_use_grouping; }
+ Value use_grouping_to_value(GlobalObject&) const;
+ void set_use_grouping(StringOrBoolean const& use_grouping);
Notation notation() const { return m_notation; }
StringView notation_string() const;
@@ -198,7 +243,7 @@ private:
Optional<CurrencySign> m_currency_sign {}; // [[CurrencySign]]
Optional<String> m_unit {}; // [[Unit]]
Optional<Unicode::Style> m_unit_display {}; // [[UnitDisplay]]
- bool m_use_grouping { false }; // [[UseGrouping]]
+ UseGrouping m_use_grouping { false }; // [[UseGrouping]]
Notation m_notation { Notation::Invalid }; // [[Notation]]
Optional<CompactDisplay> m_compact_display {}; // [[CompactDisplay]]
SignDisplay m_sign_display { SignDisplay::Invalid }; // [[SignDisplay]]
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp
index 58a9a3cfa2..bc7fef857f 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatConstructor.cpp
@@ -80,6 +80,7 @@ JS_DEFINE_NATIVE_FUNCTION(NumberFormatConstructor::supported_locales_of)
}
// 15.1.2 InitializeNumberFormat ( numberFormat, locales, options ), https://tc39.es/ecma402/#sec-initializenumberformat
+// 1.1.2 InitializeNumberFormat ( numberFormat, locales, options ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-initializenumberformat
ThrowCompletionOr<NumberFormat*> initialize_number_format(GlobalObject& global_object, NumberFormat& number_format, Value locales_value, Value options_value)
{
auto& vm = global_object.vm();
@@ -170,32 +171,71 @@ ThrowCompletionOr<NumberFormat*> initialize_number_format(GlobalObject& global_o
// 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()));
- // 21. Let compactDisplay be ? GetOption(options, "compactDisplay", "string", « "short", "long" », "short").
+ // 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").
auto compact_display = TRY(get_option(global_object, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, "short"sv));
- // 22. If notation is "compact", then
+ // 29. Let defaultUseGrouping be "auto".
+ auto default_use_grouping = "auto"sv;
+
+ // 30. If notation is "compact", then
if (number_format.notation() == NumberFormat::Notation::Compact) {
// a. Set numberFormat.[[CompactDisplay]] to compactDisplay.
number_format.set_compact_display(compact_display.as_string().string());
+
+ // b. Set defaultUseGrouping to "min2".
+ default_use_grouping = "min2"sv;
}
- // 23. Let useGrouping be ? GetOption(options, "useGrouping", "boolean", undefined, true).
- auto use_grouping = TRY(get_option(global_object, *options, vm.names.useGrouping, OptionType::Boolean, {}, true));
+ // 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));
- // 24. Set numberFormat.[[UseGrouping]] to useGrouping.
- number_format.set_use_grouping(use_grouping.as_bool());
+ // 32. Set numberFormat.[[UseGrouping]] to useGrouping.
+ number_format.set_use_grouping(use_grouping);
- // 25. Let signDisplay be ? GetOption(options, "signDisplay", "string", « "auto", "never", "always", "exceptZero" », "auto").
- auto sign_display = TRY(get_option(global_object, *options, vm.names.signDisplay, OptionType::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv }, "auto"sv));
+ // 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));
- // 26. Set numberFormat.[[SignDisplay]] to signDisplay.
+ // 34. Set numberFormat.[[SignDisplay]] to signDisplay.
number_format.set_sign_display(sign_display.as_string().string());
- // 27. Return numberFormat.
+ // 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.
return &number_format;
}
// 15.1.3 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation ), https://tc39.es/ecma402/#sec-setnfdigitoptions
+// 1.1.1 SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault, notation ), https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#sec-setnfdigitoptions
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();
@@ -218,46 +258,66 @@ ThrowCompletionOr<void> set_number_format_digit_options(GlobalObject& global_obj
// 6. Set intlObj.[[MinimumIntegerDigits]] to mnid.
intl_object.set_min_integer_digits(*min_integer_digits);
- // 7. If mnsd is not undefined or mxsd is not undefined, then
+ // 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
// a. Let hasSd be true.
- // 8. Else,
+ // 9. Else,
// a. Let hasSd be false.
bool has_significant_digits = !min_significant_digits.is_undefined() || !max_significant_digits.is_undefined();
- // 9. If mnfd is not undefined or mxfd is not undefined, then
+ // 10. If mnfd is not undefined or mxfd is not undefined, then
// a. Let hasFd be true.
- // 10. Else,
+ // 11. Else,
// a. Let hasFd be false.
bool has_fraction_digits = !min_fraction_digits.is_undefined() || !max_fraction_digits.is_undefined();
- // 11. Let needSd be hasSd.
- bool need_significant_digits = has_significant_digits;
+ // 12. Let needSd be true.
+ bool need_significant_digits = true;
+
+ // 13. Let needFd be true.
+ bool need_fraction_digits = true;
- // 12. If hasSd is true, or hasFd is false and notation is "compact", then
- // a. Let needFd be false.
- // 13. Else,
- // a. Let needFd be true.
- bool need_fraction_digits = !has_significant_digits && (has_fraction_digits || (notation != NumberFormat::Notation::Compact));
+ // 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;
+ }
+ }
- // 14. If needSd is true, then
+ // 15. If needSd is true, then
if (need_significant_digits) {
- // a. Assert: hasSd is true.
- VERIFY(has_significant_digits);
+ // 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));
- // b. Set mnsd to ? DefaultNumberOption(mnsd, 1, 21, 1).
- auto min_digits = TRY(default_number_option(global_object, min_significant_digits, 1, 21, 1));
+ // 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));
- // c. Set mxsd to ? DefaultNumberOption(mxsd, mnsd, 21, 21).
- auto max_digits = TRY(default_number_option(global_object, max_significant_digits, *min_digits, 21, 21));
+ // iii. Set intlObj.[[MinimumSignificantDigits]] to mnsd.
+ intl_object.set_min_significant_digits(*min_digits);
- // d. Set intlObj.[[MinimumSignificantDigits]] to mnsd.
- intl_object.set_min_significant_digits(*min_digits);
+ // 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);
- // e. Set intlObj.[[MaximumSignificantDigits]] to mxsd.
- intl_object.set_max_significant_digits(*max_digits);
+ // ii. Set intlObj.[[MaximumSignificantDigits]] to 21.
+ intl_object.set_max_significant_digits(21);
+ }
}
- // 15. If needFd is true, then
+ // 16. If needFd is true, then
if (need_fraction_digits) {
// a. If hasFd is true, then
if (has_fraction_digits) {
@@ -293,20 +353,46 @@ ThrowCompletionOr<void> set_number_format_digit_options(GlobalObject& global_obj
}
}
- // 16. If needSd is false and needFd is false, then
- if (!need_significant_digits && !need_fraction_digits) {
- // a. Set intlObj.[[RoundingType]] to compactRounding.
- intl_object.set_rounding_type(NumberFormatBase::RoundingType::CompactRounding);
- }
- // 17. Else if hasSd is true, then
- else if (has_significant_digits) {
- // a. Set intlObj.[[RoundingType]] to significantDigits.
- intl_object.set_rounding_type(NumberFormatBase::RoundingType::SignificantDigits);
+ // 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);
+ }
}
+
// 18. Else,
else {
- // a. Set intlObj.[[RoundingType]] to fractionDigits.
- intl_object.set_rounding_type(NumberFormatBase::RoundingType::FractionDigits);
+ // 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);
}
return {};
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatPrototype.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatPrototype.cpp
index 9f9d4771aa..907b384fdd 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormatPrototype.cpp
@@ -114,13 +114,34 @@ JS_DEFINE_NATIVE_FUNCTION(NumberFormatPrototype::resolved_options)
MUST(options->create_data_property_or_throw(vm.names.minimumSignificantDigits, Value(number_format->min_significant_digits())));
if (number_format->has_max_significant_digits())
MUST(options->create_data_property_or_throw(vm.names.maximumSignificantDigits, Value(number_format->max_significant_digits())));
- MUST(options->create_data_property_or_throw(vm.names.useGrouping, Value(number_format->use_grouping())));
+ MUST(options->create_data_property_or_throw(vm.names.useGrouping, number_format->use_grouping_to_value(global_object)));
MUST(options->create_data_property_or_throw(vm.names.notation, js_string(vm, number_format->notation_string())));
if (number_format->has_compact_display())
MUST(options->create_data_property_or_throw(vm.names.compactDisplay, js_string(vm, number_format->compact_display_string())));
MUST(options->create_data_property_or_throw(vm.names.signDisplay, js_string(vm, number_format->sign_display_string())));
+ MUST(options->create_data_property_or_throw(vm.names.roundingMode, js_string(vm, number_format->rounding_mode_string())));
+ MUST(options->create_data_property_or_throw(vm.names.roundingIncrement, Value(number_format->rounding_increment())));
+ MUST(options->create_data_property_or_throw(vm.names.trailingZeroDisplay, js_string(vm, number_format->trailing_zero_display_string())));
+
+ switch (number_format->rounding_type()) {
+ // 6. If nf.[[RoundingType]] is morePrecision, then
+ case NumberFormatBase::RoundingType::MorePrecision:
+ // a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "morePrecision").
+ MUST(options->create_data_property_or_throw(vm.names.roundingPriority, js_string(vm, "morePrecision"sv)));
+ break;
+ // 7. Else if nf.[[RoundingType]] is lessPrecision, then
+ case NumberFormatBase::RoundingType::LessPrecision:
+ // a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "lessPrecision").
+ MUST(options->create_data_property_or_throw(vm.names.roundingPriority, js_string(vm, "lessPrecision"sv)));
+ break;
+ // 8. Else,
+ default:
+ // a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "auto").
+ MUST(options->create_data_property_or_throw(vm.names.roundingPriority, js_string(vm, "auto"sv)));
+ break;
+ }
- // 5. Return options.
+ // 9. Return options.
return options;
}
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.js
index d56577db7e..46a6509175 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.js
@@ -208,6 +208,70 @@ describe("errors", () => {
new Intl.NumberFormat("en", { signDisplay: "hello!" });
}).toThrowWithMessage(RangeError, "hello! is not a valid value for option signDisplay");
});
+
+ test("roundingPriority option is invalid", () => {
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingPriority: "hello!" });
+ }).toThrowWithMessage(
+ RangeError,
+ "hello! is not a valid value for option roundingPriority"
+ );
+ });
+
+ test("roundingMode option is invalid", () => {
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingMode: "hello!" });
+ }).toThrowWithMessage(RangeError, "hello! is not a valid value for option roundingMode");
+ });
+
+ test("roundingIncrement option is invalid", () => {
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingIncrement: "hello!" });
+ }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 1 and 5000");
+
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingIncrement: 0 });
+ }).toThrowWithMessage(RangeError, "Value 0 is NaN or is not between 1 and 5000");
+
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingIncrement: 5001 });
+ }).toThrowWithMessage(RangeError, "Value 5001 is NaN or is not between 1 and 5000");
+
+ expect(() => {
+ new Intl.NumberFormat("en", {
+ roundingIncrement: 3,
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ });
+ }).toThrowWithMessage(RangeError, "3 is not a valid rounding increment");
+
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingIncrement: 5, minimumSignificantDigits: 1 });
+ }).toThrowWithMessage(
+ TypeError,
+ "5 is not a valid rounding increment for rounding type significantDigits"
+ );
+
+ expect(() => {
+ new Intl.NumberFormat("en", {
+ roundingIncrement: 5,
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 3,
+ });
+ }).toThrowWithMessage(
+ RangeError,
+ "5 is not a valid rounding increment for inequal min/max fraction digits"
+ );
+ });
+
+ test("trailingZeroDisplay option is invalid", () => {
+ expect(() => {
+ new Intl.NumberFormat("en", { trailingZeroDisplay: "hello!" });
+ }).toThrowWithMessage(
+ RangeError,
+ "hello! is not a valid value for option trailingZeroDisplay"
+ );
+ });
});
describe("normal behavior", () => {
@@ -344,10 +408,66 @@ describe("normal behavior", () => {
});
test("all valid signDisplay options", () => {
- ["auto", "never", "always", "exceptZero"].forEach(signDisplay => {
+ ["auto", "never", "always", "exceptZero", "negative"].forEach(signDisplay => {
expect(() => {
new Intl.NumberFormat("en", { signDisplay: signDisplay });
}).not.toThrow();
});
});
+
+ test("valid useGrouping options", () => {
+ ["min2", "auto", "always", false, true, ""].forEach(useGrouping => {
+ expect(() => {
+ new Intl.NumberFormat("en", { useGrouping: useGrouping });
+ }).not.toThrow();
+ });
+ });
+
+ test("all valid roundingPriority options", () => {
+ ["auto", "morePrecision", "lessPrecision"].forEach(roundingPriority => {
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingPriority: roundingPriority });
+ }).not.toThrow();
+ });
+ });
+
+ test("all valid roundingMode options", () => {
+ [
+ "ceil",
+ "floor",
+ "expand",
+ "trunc",
+ "halfCeil",
+ "halfFloor",
+ "halfExpand",
+ "halfTrunc",
+ "halfEven",
+ ].forEach(roundingMode => {
+ expect(() => {
+ new Intl.NumberFormat("en", { roundingMode: roundingMode });
+ }).not.toThrow();
+ });
+ });
+
+ test("all valid roundingIncrement options", () => {
+ [1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000].forEach(
+ roundingIncrement => {
+ expect(() => {
+ new Intl.NumberFormat("en", {
+ roundingIncrement: roundingIncrement,
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ });
+ }).not.toThrow();
+ }
+ );
+ });
+
+ test("all valid trailingZeroDisplay options", () => {
+ ["auto", "stripIfInteger"].forEach(trailingZeroDisplay => {
+ expect(() => {
+ new Intl.NumberFormat("en", { trailingZeroDisplay: trailingZeroDisplay });
+ }).not.toThrow();
+ });
+ });
});
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.resolvedOptions.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.resolvedOptions.js
index 70ebdde2df..8dafec921c 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.resolvedOptions.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.resolvedOptions.js
@@ -176,12 +176,12 @@ describe("correct behavior", () => {
});
});
- test("compact notation causes all min/max digits to be undefined by default", () => {
+ test("compact notation causes all min/max digits to be set to default values", () => {
const en = new Intl.NumberFormat("en", { notation: "compact" });
- expect(en.resolvedOptions().minimumFractionDigits).toBeUndefined();
- expect(en.resolvedOptions().maximumFractionDigits).toBeUndefined();
- expect(en.resolvedOptions().minimumSignificantDigits).toBeUndefined();
- expect(en.resolvedOptions().maximumSignificantDigits).toBeUndefined();
+ expect(en.resolvedOptions().minimumFractionDigits).toBe(0);
+ expect(en.resolvedOptions().maximumFractionDigits).toBe(0);
+ expect(en.resolvedOptions().minimumSignificantDigits).toBe(1);
+ expect(en.resolvedOptions().maximumSignificantDigits).toBe(2);
});
test("currency display and sign only defined when style is currency", () => {
@@ -276,19 +276,89 @@ describe("correct behavior", () => {
test("use grouping", () => {
const en1 = new Intl.NumberFormat("en");
- expect(en1.resolvedOptions().useGrouping).toBeTrue();
+ expect(en1.resolvedOptions().useGrouping).toBe("auto");
- const en2 = new Intl.NumberFormat("en", { useGrouping: false });
- expect(en2.resolvedOptions().useGrouping).toBeFalse();
+ const en2 = new Intl.NumberFormat("en", { notation: "compact" });
+ expect(en2.resolvedOptions().useGrouping).toBe("min2");
+
+ const en3 = new Intl.NumberFormat("en", { useGrouping: false });
+ expect(en3.resolvedOptions().useGrouping).toBeFalse();
+
+ const en4 = new Intl.NumberFormat("en", { useGrouping: true });
+ expect(en4.resolvedOptions().useGrouping).toBe("always");
+
+ ["auto", "always", "min2"].forEach(useGrouping => {
+ const en5 = new Intl.NumberFormat("en", { useGrouping: useGrouping });
+ expect(en5.resolvedOptions().useGrouping).toBe(useGrouping);
+ });
});
test("sign display", () => {
const en1 = new Intl.NumberFormat("en");
expect(en1.resolvedOptions().signDisplay).toBe("auto");
- ["auto", "never", "always", "exceptZero"].forEach(signDisplay => {
+ ["auto", "never", "always", "exceptZero", "negative"].forEach(signDisplay => {
const en2 = new Intl.NumberFormat("en", { signDisplay: signDisplay });
expect(en2.resolvedOptions().signDisplay).toBe(signDisplay);
});
});
+
+ test("rounding priority", () => {
+ const en1 = new Intl.NumberFormat("en");
+ expect(en1.resolvedOptions().roundingPriority).toBe("auto");
+
+ const en2 = new Intl.NumberFormat("en", { notation: "compact" });
+ expect(en2.resolvedOptions().roundingPriority).toBe("morePrecision");
+
+ ["auto", "morePrecision", "lessPrecision"].forEach(roundingPriority => {
+ const en3 = new Intl.NumberFormat("en", { roundingPriority: roundingPriority });
+ expect(en3.resolvedOptions().roundingPriority).toBe(roundingPriority);
+ });
+ });
+
+ test("rounding mode", () => {
+ const en1 = new Intl.NumberFormat("en");
+ expect(en1.resolvedOptions().roundingMode).toBe("halfExpand");
+
+ [
+ "ceil",
+ "floor",
+ "expand",
+ "trunc",
+ "halfCeil",
+ "halfFloor",
+ "halfExpand",
+ "halfTrunc",
+ "halfEven",
+ ].forEach(roundingMode => {
+ const en2 = new Intl.NumberFormat("en", { roundingMode: roundingMode });
+ expect(en2.resolvedOptions().roundingMode).toBe(roundingMode);
+ });
+ });
+
+ test("rounding increment", () => {
+ const en1 = new Intl.NumberFormat("en");
+ expect(en1.resolvedOptions().roundingIncrement).toBe(1);
+
+ [1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000].forEach(
+ roundingIncrement => {
+ const en2 = new Intl.NumberFormat("en", {
+ roundingIncrement: roundingIncrement,
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ });
+ expect(en2.resolvedOptions().roundingIncrement).toBe(roundingIncrement);
+ }
+ );
+ });
+
+ test("trailing zero display", () => {
+ const en1 = new Intl.NumberFormat("en");
+ expect(en1.resolvedOptions().trailingZeroDisplay).toBe("auto");
+
+ ["auto", "stripIfInteger"].forEach(trailingZeroDisplay => {
+ const en2 = new Intl.NumberFormat("en", { trailingZeroDisplay: trailingZeroDisplay });
+ expect(en2.resolvedOptions().trailingZeroDisplay).toBe(trailingZeroDisplay);
+ });
+ });
});
diff --git a/Userland/Utilities/js.cpp b/Userland/Utilities/js.cpp
index cb71990442..1d3b1b5b2d 100644
--- a/Userland/Utilities/js.cpp
+++ b/Userland/Utilities/js.cpp
@@ -747,9 +747,13 @@ static void print_intl_number_format(JS::Intl::NumberFormat const& number_format
print_value(JS::Value(number_format.max_significant_digits()), seen_objects);
}
js_out("\n useGrouping: ");
- print_value(JS::Value(number_format.use_grouping()), seen_objects);
+ print_value(number_format.use_grouping_to_value(number_format.global_object()), seen_objects);
js_out("\n roundingType: ");
print_value(js_string(number_format.vm(), number_format.rounding_type_string()), seen_objects);
+ js_out("\n roundingMode: ");
+ print_value(js_string(number_format.vm(), number_format.rounding_mode_string()), seen_objects);
+ js_out("\n roundingIncrement: ");
+ print_value(JS::Value(number_format.rounding_increment()), seen_objects);
js_out("\n notation: ");
print_value(js_string(number_format.vm(), number_format.notation_string()), seen_objects);
if (number_format.has_compact_display()) {
@@ -758,6 +762,8 @@ static void print_intl_number_format(JS::Intl::NumberFormat const& number_format
}
js_out("\n signDisplay: ");
print_value(js_string(number_format.vm(), number_format.sign_display_string()), seen_objects);
+ js_out("\n trailingZeroDisplay: ");
+ print_value(js_string(number_format.vm(), number_format.trailing_zero_display_string()), seen_objects);
}
static void print_intl_date_time_format(JS::Intl::DateTimeFormat& date_time_format, HashTable<JS::Object*>& seen_objects)