Skip to content

Commit

Permalink
LibJS: Disallow grouping separators in formatted duration fields
Browse files Browse the repository at this point in the history
This is a normative change in the Intl.DurationFormat proposal. See:
tc39/proposal-intl-duration-format@68b00f3
  • Loading branch information
trflynn89 authored and awesomekling committed Aug 14, 2024
1 parent 72f6139 commit 50dfaf8
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 17 deletions.
43 changes: 26 additions & 17 deletions Userland/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,21 +442,24 @@ Vector<DurationFormatPart> format_numeric_hours(VM& vm, DurationFormat const& du
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
}

// 9. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
// 9. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
MUST(number_format_options->create_data_property_or_throw(vm.names.useGrouping, Value { false }));

// 10. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
auto number_format = construct_number_format(vm, duration_format, number_format_options);

// 10. Let hoursParts be ! PartitionNumberPattern(nf, hoursValue).
// 11. Let hoursParts be ! PartitionNumberPattern(nf, hoursValue).
auto hours_parts = partition_number_pattern(number_format, MathematicalValue { hours_value });

// 11. For each Record { [[Type]], [[Value]] } part of hoursParts, do
// 12. For each Record { [[Type]], [[Value]] } part of hoursParts, do
result.ensure_capacity(hours_parts.size());

for (auto& part : hours_parts) {
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "hour" } to result.
result.unchecked_append({ .type = part.type, .value = move(part.value), .unit = "hour"sv });
}

// 12. Return result.
// 13. Return result.
return result;
}

Expand Down Expand Up @@ -504,21 +507,24 @@ Vector<DurationFormatPart> format_numeric_minutes(VM& vm, DurationFormat const&
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
}

// 10. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
// 10. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
MUST(number_format_options->create_data_property_or_throw(vm.names.useGrouping, Value { false }));

// 11. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
auto number_format = construct_number_format(vm, duration_format, number_format_options);

// 11. Let minutesParts be ! PartitionNumberPattern(nf, minutesValue).
// 12. Let minutesParts be ! PartitionNumberPattern(nf, minutesValue).
auto minutes_parts = partition_number_pattern(number_format, MathematicalValue { minutes_value });

// 12. For each Record { [[Type]], [[Value]] } part of minutesParts, do
// 13. For each Record { [[Type]], [[Value]] } part of minutesParts, do
result.ensure_capacity(result.size() + minutes_parts.size());

for (auto& part : minutes_parts) {
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "minute" } to result.
result.unchecked_append({ .type = part.type, .value = move(part.value), .unit = "minute"sv });
}

// 13. Return result.
// 14. Return result.
return result;
}

Expand Down Expand Up @@ -566,18 +572,21 @@ Vector<DurationFormatPart> format_numeric_seconds(VM& vm, DurationFormat const&
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
}

// 10. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
MUST(number_format_options->create_data_property_or_throw(vm.names.useGrouping, Value { false }));

u8 maximum_fraction_digits = 0;
u8 minimum_fraction_digits = 0;

// 11. If durationFormat.[[FractionalDigits]] is undefined, then
// 12. If durationFormat.[[FractionalDigits]] is undefined, then
if (!duration_format.has_fractional_digits()) {
// a. Let maximumFractionDigits be 9𝔽.
maximum_fraction_digits = 9;

// b. Let minimumFractionDigits be +0𝔽.
minimum_fraction_digits = 0;
}
// 12. Else,
// 13. Else,
else {
// a. Let maximumFractionDigits be durationFormat.[[FractionalDigits]].
maximum_fraction_digits = duration_format.fractional_digits();
Expand All @@ -586,32 +595,32 @@ Vector<DurationFormatPart> format_numeric_seconds(VM& vm, DurationFormat const&
minimum_fraction_digits = duration_format.fractional_digits();
}

// 13. Perform ! CreateDataPropertyOrThrow(nfOpts, "maximumFractionDigits", maximumFractionDigits).
// 14. Perform ! CreateDataPropertyOrThrow(nfOpts, "maximumFractionDigits", maximumFractionDigits).
MUST(number_format_options->create_data_property_or_throw(vm.names.maximumFractionDigits, Value { maximum_fraction_digits }));

// 14. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumFractionDigits", minimumFractionDigits).
// 15. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumFractionDigits", minimumFractionDigits).
MUST(number_format_options->create_data_property_or_throw(vm.names.minimumFractionDigits, Value { minimum_fraction_digits }));

// 15. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode", "trunc").
// 16. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode", "trunc").
MUST(number_format_options->create_data_property_or_throw(vm.names.roundingMode, PrimitiveString::create(vm, "trunc"sv)));

// FIXME: We obviously have to create the NumberFormat object after its options are fully initialized.
// https://github.com/tc39/proposal-intl-duration-format/pull/203
// 10. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
// 11. Let nf be ! Construct(%NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
auto number_format = construct_number_format(vm, duration_format, number_format_options);

// 16. Let secondsParts be ! PartitionNumberPattern(nf, secondsValue).
// 17. Let secondsParts be ! PartitionNumberPattern(nf, secondsValue).
auto seconds_parts = partition_number_pattern(number_format, MathematicalValue { seconds_value });

// 17. For each Record { [[Type]], [[Value]] } part of secondsParts, do
// 18. For each Record { [[Type]], [[Value]] } part of secondsParts, do
result.ensure_capacity(result.size() + seconds_parts.size());

for (auto& part : seconds_parts) {
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "second" } to result.
result.unchecked_append({ .type = part.type, .value = move(part.value), .unit = "second"sv });
}

// 18. Return result.
// 19. Return result.
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,20 @@ describe("correct behavior", () => {
const de = new Intl.DurationFormat("de", { style: "digital" });
expect(de.format(duration)).toBe("-1 J, 2 Mon., 3 Wo., 4 Tg. und 5:06:07,008009011");
});

test("formatted fields do not have grouping separators", () => {
const duration = {
hours: 123456,
minutes: 456789,
seconds: 789123,
};

const en = new Intl.DurationFormat("en", { style: "digital" });
expect(en.format(duration)).toBe("123456:456789:789123");

const de = new Intl.DurationFormat("de", { style: "digital" });
expect(de.format(duration)).toBe("123456:456789:789123");
});
});

describe("errors", () => {
Expand Down

0 comments on commit 50dfaf8

Please sign in to comment.