LCOV - code coverage report
Current view: top level - src/objects - js-relative-time-format.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 139 162 85.8 %
Date: 2019-04-17 Functions: 17 19 89.5 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_INTL_SUPPORT
       6             : #error Internationalization is expected to be enabled.
       7             : #endif  // V8_INTL_SUPPORT
       8             : 
       9             : #include "src/objects/js-relative-time-format.h"
      10             : 
      11             : #include <map>
      12             : #include <memory>
      13             : #include <string>
      14             : 
      15             : #include "src/heap/factory.h"
      16             : #include "src/isolate.h"
      17             : #include "src/objects-inl.h"
      18             : #include "src/objects/intl-objects.h"
      19             : #include "src/objects/js-number-format.h"
      20             : #include "src/objects/js-relative-time-format-inl.h"
      21             : #include "unicode/numfmt.h"
      22             : #include "unicode/reldatefmt.h"
      23             : 
      24             : namespace v8 {
      25             : namespace internal {
      26             : 
      27             : namespace {
      28         738 : UDateRelativeDateTimeFormatterStyle getIcuStyle(
      29             :     JSRelativeTimeFormat::Style style) {
      30         738 :   switch (style) {
      31             :     case JSRelativeTimeFormat::Style::LONG:
      32             :       return UDAT_STYLE_LONG;
      33             :     case JSRelativeTimeFormat::Style::SHORT:
      34         108 :       return UDAT_STYLE_SHORT;
      35             :     case JSRelativeTimeFormat::Style::NARROW:
      36          81 :       return UDAT_STYLE_NARROW;
      37             :     case JSRelativeTimeFormat::Style::COUNT:
      38           0 :       UNREACHABLE();
      39             :   }
      40           0 : }
      41             : }  // namespace
      42             : 
      43           0 : JSRelativeTimeFormat::Style JSRelativeTimeFormat::getStyle(const char* str) {
      44           0 :   if (strcmp(str, "long") == 0) return JSRelativeTimeFormat::Style::LONG;
      45           0 :   if (strcmp(str, "short") == 0) return JSRelativeTimeFormat::Style::SHORT;
      46           0 :   if (strcmp(str, "narrow") == 0) return JSRelativeTimeFormat::Style::NARROW;
      47           0 :   UNREACHABLE();
      48             : }
      49             : 
      50           0 : JSRelativeTimeFormat::Numeric JSRelativeTimeFormat::getNumeric(
      51             :     const char* str) {
      52           0 :   if (strcmp(str, "auto") == 0) return JSRelativeTimeFormat::Numeric::AUTO;
      53           0 :   if (strcmp(str, "always") == 0) return JSRelativeTimeFormat::Numeric::ALWAYS;
      54           0 :   UNREACHABLE();
      55             : }
      56             : 
      57         783 : MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
      58             :     Isolate* isolate, Handle<JSRelativeTimeFormat> relative_time_format_holder,
      59             :     Handle<Object> locales, Handle<Object> input_options) {
      60             :   relative_time_format_holder->set_flags(0);
      61             : 
      62             :   // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
      63             :   Maybe<std::vector<std::string>> maybe_requested_locales =
      64         783 :       Intl::CanonicalizeLocaleList(isolate, locales);
      65         783 :   MAYBE_RETURN(maybe_requested_locales, Handle<JSRelativeTimeFormat>());
      66             :   std::vector<std::string> requested_locales =
      67         783 :       maybe_requested_locales.FromJust();
      68             : 
      69             :   // 2. If options is undefined, then
      70             :   Handle<JSReceiver> options;
      71         783 :   if (input_options->IsUndefined(isolate)) {
      72             :     // 2. a. Let options be ObjectCreate(null).
      73         324 :     options = isolate->factory()->NewJSObjectWithNullProto();
      74             :     // 3. Else
      75             :   } else {
      76             :     // 3. a. Let options be ? ToObject(options).
      77         918 :     ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
      78             :                                Object::ToObject(isolate, input_options),
      79             :                                JSRelativeTimeFormat);
      80             :   }
      81             : 
      82             :   // 4. Let opt be a new Record.
      83             :   // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «
      84             :   // "lookup", "best fit" », "best fit").
      85             :   // 6. Set opt.[[localeMatcher]] to matcher.
      86             :   Maybe<Intl::MatcherOption> maybe_locale_matcher =
      87         783 :       Intl::GetLocaleMatcher(isolate, options, "Intl.RelativeTimeFormat");
      88         783 :   MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSRelativeTimeFormat>());
      89             :   Intl::MatcherOption matcher = maybe_locale_matcher.FromJust();
      90             : 
      91             :   // 7. Let localeData be %RelativeTimeFormat%.[[LocaleData]].
      92             :   // 8. Let r be
      93             :   // ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]],
      94             :   //               requestedLocales, opt,
      95             :   //               %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData).
      96             :   Intl::ResolvedLocale r =
      97             :       Intl::ResolveLocale(isolate, JSRelativeTimeFormat::GetAvailableLocales(),
      98        3780 :                           requested_locales, matcher, {"nu"});
      99             : 
     100             :   // 9. Let locale be r.[[Locale]].
     101             :   // 10. Set relativeTimeFormat.[[Locale]] to locale.
     102             :   // 11. Let dataLocale be r.[[DataLocale]].
     103             :   Handle<String> locale_str =
     104         756 :       isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str());
     105         756 :   relative_time_format_holder->set_locale(*locale_str);
     106             : 
     107             :   // 12. Let s be ? GetOption(options, "style", "string",
     108             :   //                          «"long", "short", "narrow"», "long").
     109             :   Maybe<Style> maybe_style = Intl::GetStringOption<Style>(
     110             :       isolate, options, "style", "Intl.RelativeTimeFormat",
     111             :       {"long", "short", "narrow"}, {Style::LONG, Style::SHORT, Style::NARROW},
     112        2268 :       Style::LONG);
     113         756 :   MAYBE_RETURN(maybe_style, MaybeHandle<JSRelativeTimeFormat>());
     114             :   Style style_enum = maybe_style.FromJust();
     115             : 
     116             :   // 13. Set relativeTimeFormat.[[Style]] to s.
     117         747 :   relative_time_format_holder->set_style(style_enum);
     118             : 
     119             :   // 14. Let numeric be ? GetOption(options, "numeric", "string",
     120             :   //                                «"always", "auto"», "always").
     121             :   Maybe<Numeric> maybe_numeric = Intl::GetStringOption<Numeric>(
     122             :       isolate, options, "numeric", "Intl.RelativeTimeFormat",
     123        2241 :       {"always", "auto"}, {Numeric::ALWAYS, Numeric::AUTO}, Numeric::ALWAYS);
     124         747 :   MAYBE_RETURN(maybe_numeric, MaybeHandle<JSRelativeTimeFormat>());
     125             :   Numeric numeric_enum = maybe_numeric.FromJust();
     126             : 
     127             :   // 15. Set relativeTimeFormat.[[Numeric]] to numeric.
     128         738 :   relative_time_format_holder->set_numeric(numeric_enum);
     129             : 
     130        1476 :   icu::Locale icu_locale = r.icu_locale;
     131         738 :   UErrorCode status = U_ZERO_ERROR;
     132             : 
     133             :   // 19. Let relativeTimeFormat.[[NumberFormat]] be
     134             :   //     ? Construct(%NumberFormat%, « nfLocale, nfOptions »).
     135             :   icu::NumberFormat* number_format =
     136         738 :       icu::NumberFormat::createInstance(icu_locale, UNUM_DECIMAL, status);
     137         738 :   if (U_FAILURE(status)) {
     138           0 :     delete number_format;
     139           0 :     FATAL("Failed to create ICU number format, are ICU data files missing?");
     140             :   }
     141         738 :   CHECK_NOT_NULL(number_format);
     142             : 
     143             :   // Change UDISPCTX_CAPITALIZATION_NONE to other values if
     144             :   // ECMA402 later include option to change capitalization.
     145             :   // Ref: https://github.com/tc39/proposal-intl-relative-time/issues/11
     146             :   icu::RelativeDateTimeFormatter* icu_formatter =
     147             :       new icu::RelativeDateTimeFormatter(icu_locale, number_format,
     148             :                                          getIcuStyle(style_enum),
     149         738 :                                          UDISPCTX_CAPITALIZATION_NONE, status);
     150         738 :   if (U_FAILURE(status)) {
     151           0 :     delete icu_formatter;
     152             :     FATAL(
     153             :         "Failed to create ICU relative date time formatter, are ICU data files "
     154           0 :         "missing?");
     155             :   }
     156         738 :   CHECK_NOT_NULL(icu_formatter);
     157             : 
     158             :   Handle<Managed<icu::RelativeDateTimeFormatter>> managed_formatter =
     159             :       Managed<icu::RelativeDateTimeFormatter>::FromRawPtr(isolate, 0,
     160         738 :                                                           icu_formatter);
     161             : 
     162             :   // 21. Set relativeTimeFormat.[[InitializedRelativeTimeFormat]] to true.
     163         738 :   relative_time_format_holder->set_icu_formatter(*managed_formatter);
     164             : 
     165             :   // 22. Return relativeTimeFormat.
     166         738 :   return relative_time_format_holder;
     167             : }
     168             : 
     169         495 : Handle<JSObject> JSRelativeTimeFormat::ResolvedOptions(
     170             :     Isolate* isolate, Handle<JSRelativeTimeFormat> format_holder) {
     171             :   Factory* factory = isolate->factory();
     172         495 :   Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
     173             :   Handle<String> locale(format_holder->locale(), isolate);
     174         495 :   JSObject::AddProperty(isolate, result, factory->locale_string(), locale,
     175         495 :                         NONE);
     176         990 :   JSObject::AddProperty(isolate, result, factory->style_string(),
     177         495 :                         format_holder->StyleAsString(), NONE);
     178         990 :   JSObject::AddProperty(isolate, result, factory->numeric_string(),
     179         495 :                         format_holder->NumericAsString(), NONE);
     180        1485 :   std::string locale_str(format_holder->locale()->ToCString().get());
     181         990 :   icu::Locale icu_locale = Intl::CreateICULocale(locale_str);
     182         495 :   std::string numbering_system = Intl::GetNumberingSystem(icu_locale);
     183         990 :   JSObject::AddProperty(
     184             :       isolate, result, factory->numberingSystem_string(),
     185         495 :       factory->NewStringFromAsciiChecked(numbering_system.c_str()), NONE);
     186         990 :   return result;
     187             : }
     188             : 
     189         495 : Handle<String> JSRelativeTimeFormat::StyleAsString() const {
     190         495 :   switch (style()) {
     191             :     case Style::LONG:
     192             :       return GetReadOnlyRoots().long_string_handle();
     193             :     case Style::SHORT:
     194             :       return GetReadOnlyRoots().short_string_handle();
     195             :     case Style::NARROW:
     196             :       return GetReadOnlyRoots().narrow_string_handle();
     197             :     case Style::COUNT:
     198           0 :       UNREACHABLE();
     199             :   }
     200           0 : }
     201             : 
     202         495 : Handle<String> JSRelativeTimeFormat::NumericAsString() const {
     203         495 :   switch (numeric()) {
     204             :     case Numeric::ALWAYS:
     205             :       return GetReadOnlyRoots().always_string_handle();
     206             :     case Numeric::AUTO:
     207             :       return GetReadOnlyRoots().auto_string_handle();
     208             :     case Numeric::COUNT:
     209           0 :       UNREACHABLE();
     210             :   }
     211           0 : }
     212             : 
     213             : namespace {
     214             : 
     215        4239 : Handle<String> UnitAsString(Isolate* isolate, URelativeDateTimeUnit unit_enum) {
     216             :   Factory* factory = isolate->factory();
     217        4239 :   switch (unit_enum) {
     218             :     case UDAT_REL_UNIT_SECOND:
     219             :       return factory->second_string();
     220             :     case UDAT_REL_UNIT_MINUTE:
     221             :       return factory->minute_string();
     222             :     case UDAT_REL_UNIT_HOUR:
     223             :       return factory->hour_string();
     224             :     case UDAT_REL_UNIT_DAY:
     225             :       return factory->day_string();
     226             :     case UDAT_REL_UNIT_WEEK:
     227             :       return factory->week_string();
     228             :     case UDAT_REL_UNIT_MONTH:
     229             :       return factory->month_string();
     230             :     case UDAT_REL_UNIT_QUARTER:
     231             :       return factory->quarter_string();
     232             :     case UDAT_REL_UNIT_YEAR:
     233             :       return factory->year_string();
     234             :     default:
     235           0 :       UNREACHABLE();
     236             :   }
     237             : }
     238             : 
     239        4419 : bool GetURelativeDateTimeUnit(Handle<String> unit,
     240             :                               URelativeDateTimeUnit* unit_enum) {
     241        4419 :   std::unique_ptr<char[]> unit_str = unit->ToCString();
     242        8370 :   if ((strcmp("second", unit_str.get()) == 0) ||
     243        3951 :       (strcmp("seconds", unit_str.get()) == 0)) {
     244         531 :     *unit_enum = UDAT_REL_UNIT_SECOND;
     245        7308 :   } else if ((strcmp("minute", unit_str.get()) == 0) ||
     246        3420 :              (strcmp("minutes", unit_str.get()) == 0)) {
     247         513 :     *unit_enum = UDAT_REL_UNIT_MINUTE;
     248        6282 :   } else if ((strcmp("hour", unit_str.get()) == 0) ||
     249        2907 :              (strcmp("hours", unit_str.get()) == 0)) {
     250         513 :     *unit_enum = UDAT_REL_UNIT_HOUR;
     251        5139 :   } else if ((strcmp("day", unit_str.get()) == 0) ||
     252        2277 :              (strcmp("days", unit_str.get()) == 0)) {
     253         630 :     *unit_enum = UDAT_REL_UNIT_DAY;
     254        3996 :   } else if ((strcmp("week", unit_str.get()) == 0) ||
     255        1764 :              (strcmp("weeks", unit_str.get()) == 0)) {
     256         513 :     *unit_enum = UDAT_REL_UNIT_WEEK;
     257        2970 :   } else if ((strcmp("month", unit_str.get()) == 0) ||
     258        1251 :              (strcmp("months", unit_str.get()) == 0)) {
     259         513 :     *unit_enum = UDAT_REL_UNIT_MONTH;
     260        1944 :   } else if ((strcmp("quarter", unit_str.get()) == 0) ||
     261         738 :              (strcmp("quarters", unit_str.get()) == 0)) {
     262         513 :     *unit_enum = UDAT_REL_UNIT_QUARTER;
     263         918 :   } else if ((strcmp("year", unit_str.get()) == 0) ||
     264         225 :              (strcmp("years", unit_str.get()) == 0)) {
     265         513 :     *unit_enum = UDAT_REL_UNIT_YEAR;
     266             :   } else {
     267             :     return false;
     268             :   }
     269             :   return true;
     270             : }
     271             : 
     272             : template <typename T>
     273        6453 : MaybeHandle<T> FormatCommon(
     274             :     Isolate* isolate, Handle<JSRelativeTimeFormat> format,
     275             :     Handle<Object> value_obj, Handle<Object> unit_obj, const char* func_name,
     276             :     MaybeHandle<T> (*formatToResult)(Isolate*,
     277             :                                      const icu::FormattedRelativeDateTime&,
     278             :                                      Handle<Object>, Handle<String>)) {
     279             :   // 3. Let value be ? ToNumber(value).
     280             :   Handle<Object> value;
     281       12906 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
     282             :                              Object::ToNumber(isolate, value_obj), T);
     283             :   double number = value->Number();
     284             :   // 4. Let unit be ? ToString(unit).
     285             :   Handle<String> unit;
     286       12906 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, unit, Object::ToString(isolate, unit_obj),
     287             :                              T);
     288             :   // 4. If isFinite(value) is false, then throw a RangeError exception.
     289        6453 :   if (!std::isfinite(number)) {
     290        6102 :     THROW_NEW_ERROR(
     291             :         isolate,
     292             :         NewRangeError(MessageTemplate::kNotFiniteNumber,
     293             :                       isolate->factory()->NewStringFromAsciiChecked(func_name)),
     294             :         T);
     295             :   }
     296             :   icu::RelativeDateTimeFormatter* formatter = format->icu_formatter()->raw();
     297        4419 :   CHECK_NOT_NULL(formatter);
     298             :   URelativeDateTimeUnit unit_enum;
     299        4419 :   if (!GetURelativeDateTimeUnit(unit, &unit_enum)) {
     300         540 :     THROW_NEW_ERROR(
     301             :         isolate,
     302             :         NewRangeError(MessageTemplate::kInvalidUnit,
     303             :                       isolate->factory()->NewStringFromAsciiChecked(func_name),
     304             :                       unit),
     305             :         T);
     306             :   }
     307        4239 :   UErrorCode status = U_ZERO_ERROR;
     308             :   icu::FormattedRelativeDateTime formatted =
     309             :       (format->numeric() == JSRelativeTimeFormat::Numeric::ALWAYS)
     310             :           ? formatter->formatNumericToValue(number, unit_enum, status)
     311        8478 :           : formatter->formatToValue(number, unit_enum, status);
     312        4239 :   if (U_FAILURE(status)) {
     313           0 :     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), T);
     314             :   }
     315        4239 :   return formatToResult(isolate, formatted, value,
     316        4239 :                         UnitAsString(isolate, unit_enum));
     317             : }
     318             : 
     319        3816 : MaybeHandle<String> FormatToString(
     320             :     Isolate* isolate, const icu::FormattedRelativeDateTime& formatted,
     321             :     Handle<Object> value, Handle<String> unit) {
     322        3816 :   UErrorCode status = U_ZERO_ERROR;
     323        7632 :   icu::UnicodeString result = formatted.toString(status);
     324        3816 :   if (U_FAILURE(status)) {
     325           0 :     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), String);
     326             :   }
     327        3816 :   return Intl::ToString(isolate, result);
     328             : }
     329             : 
     330         531 : Maybe<bool> AddLiteral(Isolate* isolate, Handle<JSArray> array,
     331             :                        const icu::UnicodeString& string, int32_t index,
     332             :                        int32_t start, int32_t limit) {
     333             :   Handle<String> substring;
     334        1062 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     335             :       isolate, substring, Intl::ToString(isolate, string, start, limit),
     336             :       Nothing<bool>());
     337             :   Intl::AddElement(isolate, array, index, isolate->factory()->literal_string(),
     338         531 :                    substring);
     339             :   return Just(true);
     340             : }
     341             : 
     342         450 : Maybe<bool> AddUnit(Isolate* isolate, Handle<JSArray> array,
     343             :                     const icu::UnicodeString& string, int32_t index,
     344             :                     int32_t start, int32_t limit, int32_t field_id,
     345             :                     Handle<Object> value, Handle<String> unit) {
     346             :   Handle<String> substring;
     347         900 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     348             :       isolate, substring, Intl::ToString(isolate, string, start, limit),
     349             :       Nothing<bool>());
     350         450 :   Intl::AddElement(isolate, array, index,
     351             :                    Intl::NumberFieldToType(isolate, value, field_id), substring,
     352         450 :                    isolate->factory()->unit_string(), unit);
     353             :   return Just(true);
     354             : }
     355             : 
     356         423 : MaybeHandle<JSArray> FormatToJSArray(
     357             :     Isolate* isolate, const icu::FormattedRelativeDateTime& formatted,
     358             :     Handle<Object> value, Handle<String> unit) {
     359         423 :   UErrorCode status = U_ZERO_ERROR;
     360         846 :   icu::UnicodeString string = formatted.toString(status);
     361             : 
     362             :   Factory* factory = isolate->factory();
     363             :   Handle<JSArray> array = factory->NewJSArray(0);
     364         846 :   icu::ConstrainedFieldPosition cfpos;
     365         423 :   cfpos.constrainCategory(UFIELD_CATEGORY_NUMBER);
     366             :   int32_t index = 0;
     367             : 
     368             :   int32_t previous_end = 0;
     369             :   Handle<String> substring;
     370             :   std::vector<std::pair<int32_t, int32_t>> groups;
     371         864 :   while (formatted.nextPosition(cfpos, status) && U_SUCCESS(status)) {
     372             :     int32_t category = cfpos.getCategory();
     373             :     int32_t field = cfpos.getField();
     374             :     int32_t start = cfpos.getStart();
     375             :     int32_t limit = cfpos.getLimit();
     376         441 :     if (category == UFIELD_CATEGORY_NUMBER) {
     377         441 :       if (field == UNUM_GROUPING_SEPARATOR_FIELD) {
     378           9 :         groups.push_back(std::pair<int32_t, int32_t>(start, limit));
     379           9 :         continue;
     380             :       }
     381         432 :       if (start > previous_end) {
     382             :         Maybe<bool> maybe_added =
     383         108 :             AddLiteral(isolate, array, string, index++, previous_end, start);
     384         108 :         MAYBE_RETURN(maybe_added, Handle<JSArray>());
     385             :       }
     386         432 :       if (field == UNUM_INTEGER_FIELD) {
     387         423 :         for (auto start_limit : groups) {
     388           9 :           if (start_limit.first > start) {
     389             :             Maybe<bool> maybe_added =
     390             :                 AddUnit(isolate, array, string, index++, start,
     391           9 :                         start_limit.first, field, value, unit);
     392           9 :             MAYBE_RETURN(maybe_added, Handle<JSArray>());
     393             :             maybe_added = AddUnit(isolate, array, string, index++,
     394             :                                   start_limit.first, start_limit.second,
     395           9 :                                   UNUM_GROUPING_SEPARATOR_FIELD, value, unit);
     396           9 :             MAYBE_RETURN(maybe_added, Handle<JSArray>());
     397             :             start = start_limit.second;
     398             :           }
     399             :         }
     400             :       }
     401             :       Maybe<bool> maybe_added = AddUnit(isolate, array, string, index++, start,
     402         432 :                                         limit, field, value, unit);
     403         432 :       MAYBE_RETURN(maybe_added, Handle<JSArray>());
     404             :       previous_end = limit;
     405             :     }
     406             :   }
     407         423 :   if (U_FAILURE(status)) {
     408           0 :     THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), JSArray);
     409             :   }
     410         423 :   if (string.length() > previous_end) {
     411             :     Maybe<bool> maybe_added = AddLiteral(isolate, array, string, index,
     412         423 :                                          previous_end, string.length());
     413         423 :     MAYBE_RETURN(maybe_added, Handle<JSArray>());
     414             :   }
     415             : 
     416         423 :   JSObject::ValidateElements(*array);
     417         423 :   return array;
     418             : }
     419             : 
     420             : }  // namespace
     421             : 
     422        5796 : MaybeHandle<String> JSRelativeTimeFormat::Format(
     423             :     Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
     424             :     Handle<JSRelativeTimeFormat> format) {
     425             :   return FormatCommon<String>(isolate, format, value_obj, unit_obj,
     426             :                               "Intl.RelativeTimeFormat.prototype.format",
     427        5796 :                               FormatToString);
     428             : }
     429             : 
     430         657 : MaybeHandle<JSArray> JSRelativeTimeFormat::FormatToParts(
     431             :     Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
     432             :     Handle<JSRelativeTimeFormat> format) {
     433             :   return FormatCommon<JSArray>(
     434             :       isolate, format, value_obj, unit_obj,
     435         657 :       "Intl.RelativeTimeFormat.prototype.formatToParts", FormatToJSArray);
     436             : }
     437             : 
     438          41 : const std::set<std::string>& JSRelativeTimeFormat::GetAvailableLocales() {
     439             :   // Since RelativeTimeFormatter does not have a method to list all
     440             :   // available locales, work around by calling the DateFormat.
     441         797 :   return Intl::GetAvailableLocalesForDateFormat();
     442             : }
     443             : 
     444             : }  // namespace internal
     445      121996 : }  // namespace v8

Generated by: LCOV version 1.10