mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:07:35 +00:00
LibJS: Implement Intl.NumberFormat V3's [[TrailingZeroDisplay]] changes
This commit is contained in:
parent
a712c7b5e1
commit
37ab7cc694
2 changed files with 68 additions and 5 deletions
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||||
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
#include <LibJS/Runtime/Array.h>
|
#include <LibJS/Runtime/Array.h>
|
||||||
#include <LibJS/Runtime/BigInt.h>
|
#include <LibJS/Runtime/BigInt.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
@ -449,6 +450,15 @@ static ALWAYS_INLINE bool is_zero(Value number)
|
||||||
return number.as_bigint().big_integer().is_zero();
|
return number.as_bigint().big_integer().is_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool modulo_is_zero(Value lhs, i8 rhs)
|
||||||
|
{
|
||||||
|
if (lhs.is_number())
|
||||||
|
return modulo(lhs.as_double(), rhs) == 0;
|
||||||
|
|
||||||
|
auto rhs_bigint = Crypto::SignedBigInteger::create_from(rhs);
|
||||||
|
return modulo(lhs.as_bigint().big_integer(), rhs_bigint).is_zero();
|
||||||
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE bool is_greater_than(Value number, i64 rhs)
|
static ALWAYS_INLINE bool is_greater_than(Value number, i64 rhs)
|
||||||
{
|
{
|
||||||
if (number.is_number())
|
if (number.is_number())
|
||||||
|
@ -560,13 +570,22 @@ FormatResult format_numeric_to_string(GlobalObject& global_object, NumberFormatB
|
||||||
// 7. Let string be result.[[FormattedString]].
|
// 7. Let string be result.[[FormattedString]].
|
||||||
auto string = move(result.formatted_string);
|
auto string = move(result.formatted_string);
|
||||||
|
|
||||||
// 8. Let int be result.[[IntegerDigitsCount]].
|
// 8. If intlObject.[[TrailingZeroDisplay]] is "stripIfInteger" and x modulo 1 = 0, then
|
||||||
|
if ((intl_object.trailing_zero_display() == NumberFormat::TrailingZeroDisplay::StripIfInteger) && modulo_is_zero(number, 1)) {
|
||||||
|
// a. If string contains ".", then
|
||||||
|
if (auto index = string.find('.'); index.has_value()) {
|
||||||
|
// i. Set string to the substring of string from index 0 to the index of ".".
|
||||||
|
string = string.substring(0, *index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. Let int be result.[[IntegerDigitsCount]].
|
||||||
int digits = result.digits;
|
int digits = result.digits;
|
||||||
|
|
||||||
// 9. Let minInteger be intlObject.[[MinimumIntegerDigits]].
|
// 10. Let minInteger be intlObject.[[MinimumIntegerDigits]].
|
||||||
int min_integer = intl_object.min_integer_digits();
|
int min_integer = intl_object.min_integer_digits();
|
||||||
|
|
||||||
// 10. If int < minInteger, then
|
// 11. If int < minInteger, then
|
||||||
if (digits < min_integer) {
|
if (digits < min_integer) {
|
||||||
// a. Let forwardZeros be the String consisting of minInteger–int occurrences of the character "0".
|
// a. Let forwardZeros be the String consisting of minInteger–int occurrences of the character "0".
|
||||||
auto forward_zeros = String::repeated('0', min_integer - digits);
|
auto forward_zeros = String::repeated('0', min_integer - digits);
|
||||||
|
@ -575,13 +594,13 @@ FormatResult format_numeric_to_string(GlobalObject& global_object, NumberFormatB
|
||||||
string = String::formatted("{}{}", forward_zeros, string);
|
string = String::formatted("{}{}", forward_zeros, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11. If isNegative, then
|
// 12. If isNegative, then
|
||||||
if (is_negative) {
|
if (is_negative) {
|
||||||
// a. Let x be -x.
|
// a. Let x be -x.
|
||||||
number = multiply(global_object, number, -1);
|
number = multiply(global_object, number, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12. Return the Record { [[RoundedNumber]]: x, [[FormattedString]]: string }.
|
// 13. Return the Record { [[RoundedNumber]]: x, [[FormattedString]]: string }.
|
||||||
return { move(string), number };
|
return { move(string), number };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -567,6 +567,50 @@ describe("style=decimal", () => {
|
||||||
expect(nf("ar", undefined, 2, undefined, 2).format(1.23)).toBe("\u0661\u066b\u0662\u0663");
|
expect(nf("ar", undefined, 2, undefined, 2).format(1.23)).toBe("\u0661\u066b\u0662\u0663");
|
||||||
expect(nf("ar", undefined, 3, undefined, 1).format(1.23)).toBe("\u0661\u066b\u0662\u0663");
|
expect(nf("ar", undefined, 3, undefined, 1).format(1.23)).toBe("\u0661\u066b\u0662\u0663");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("trailingZeroDisplay=auto", () => {
|
||||||
|
const en = new Intl.NumberFormat("en", {
|
||||||
|
trailingZeroDisplay: "auto",
|
||||||
|
minimumSignificantDigits: 5,
|
||||||
|
});
|
||||||
|
expect(en.format(1)).toBe("1.0000");
|
||||||
|
expect(en.format(1n)).toBe("1.0000");
|
||||||
|
expect(en.format(12)).toBe("12.000");
|
||||||
|
expect(en.format(12n)).toBe("12.000");
|
||||||
|
expect(en.format(1.2)).toBe("1.2000");
|
||||||
|
|
||||||
|
const ar = new Intl.NumberFormat("ar", {
|
||||||
|
trailingZeroDisplay: "auto",
|
||||||
|
minimumSignificantDigits: 5,
|
||||||
|
});
|
||||||
|
expect(ar.format(1)).toBe("\u0661\u066b\u0660\u0660\u0660\u0660");
|
||||||
|
expect(ar.format(1n)).toBe("\u0661\u066b\u0660\u0660\u0660\u0660");
|
||||||
|
expect(ar.format(12)).toBe("\u0661\u0662\u066b\u0660\u0660\u0660");
|
||||||
|
expect(ar.format(12n)).toBe("\u0661\u0662\u066b\u0660\u0660\u0660");
|
||||||
|
expect(ar.format(1.2)).toBe("\u0661\u066b\u0662\u0660\u0660\u0660");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("trailingZeroDisplay=stripIfInteger", () => {
|
||||||
|
const en = new Intl.NumberFormat("en", {
|
||||||
|
trailingZeroDisplay: "stripIfInteger",
|
||||||
|
minimumSignificantDigits: 5,
|
||||||
|
});
|
||||||
|
expect(en.format(1)).toBe("1");
|
||||||
|
expect(en.format(1n)).toBe("1");
|
||||||
|
expect(en.format(12)).toBe("12");
|
||||||
|
expect(en.format(12n)).toBe("12");
|
||||||
|
expect(en.format(1.2)).toBe("1.2000");
|
||||||
|
|
||||||
|
const ar = new Intl.NumberFormat("ar", {
|
||||||
|
trailingZeroDisplay: "stripIfInteger",
|
||||||
|
minimumSignificantDigits: 5,
|
||||||
|
});
|
||||||
|
expect(ar.format(1)).toBe("\u0661");
|
||||||
|
expect(ar.format(1n)).toBe("\u0661");
|
||||||
|
expect(ar.format(12)).toBe("\u0661\u0662");
|
||||||
|
expect(ar.format(12n)).toBe("\u0661\u0662");
|
||||||
|
expect(ar.format(1.2)).toBe("\u0661\u066b\u0662\u0660\u0660\u0660");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("style=percent", () => {
|
describe("style=percent", () => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue