14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/js_number_format.h"
174514f5e3Sopenharmony_ci#include "ecmascript/ecma_context.h"
184514f5e3Sopenharmony_ci#include "ecmascript/js_function.h"
194514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript {
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_ciconst std::vector<StyleOption> JSNumberFormat::STYLE_OPTION = {
244514f5e3Sopenharmony_ci    StyleOption::DECIMAL, StyleOption::PERCENT, StyleOption::CURRENCY, StyleOption::UNIT
254514f5e3Sopenharmony_ci};
264514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::STYLE_OPTION_NAME = {
274514f5e3Sopenharmony_ci    "decimal", "percent", "currency", "unit"
284514f5e3Sopenharmony_ci};
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_ciconst std::vector<CurrencyDisplayOption> JSNumberFormat::CURRENCY_DISPLAY_OPTION = {
314514f5e3Sopenharmony_ci    CurrencyDisplayOption::CODE, CurrencyDisplayOption::SYMBOL,
324514f5e3Sopenharmony_ci    CurrencyDisplayOption::NARROWSYMBOL, CurrencyDisplayOption::NAME
334514f5e3Sopenharmony_ci};
344514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::CURRENCY_DISPLAY_OPTION_NAME = {
354514f5e3Sopenharmony_ci    "code", "symbol", "narrowSymbol", "name"
364514f5e3Sopenharmony_ci};
374514f5e3Sopenharmony_ci
384514f5e3Sopenharmony_ciconst std::vector<CurrencySignOption> JSNumberFormat::CURRENCY_SIGN_OPTION = {
394514f5e3Sopenharmony_ci    CurrencySignOption::STANDARD, CurrencySignOption::ACCOUNTING
404514f5e3Sopenharmony_ci};
414514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::CURRENCY_SIGN_OPTION_NAME = {"standard", "accounting"};
424514f5e3Sopenharmony_ci
434514f5e3Sopenharmony_ciconst std::vector<UnitDisplayOption> JSNumberFormat::UNIT_DISPLAY_OPTION = {
444514f5e3Sopenharmony_ci    UnitDisplayOption::SHORT, UnitDisplayOption::NARROW, UnitDisplayOption::LONG
454514f5e3Sopenharmony_ci};
464514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::UNIT_DISPLAY_OPTION_NAME = {"short", "narrow", "long"};
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ciconst std::vector<LocaleMatcherOption> JSNumberFormat::LOCALE_MATCHER_OPTION = {
494514f5e3Sopenharmony_ci    LocaleMatcherOption::LOOKUP, LocaleMatcherOption::BEST_FIT
504514f5e3Sopenharmony_ci};
514514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::LOCALE_MATCHER_OPTION_NAME = {"lookup", "best fit"};
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_ciconst std::vector<NotationOption> JSNumberFormat::NOTATION_OPTION = {
544514f5e3Sopenharmony_ci    NotationOption::STANDARD, NotationOption::SCIENTIFIC,
554514f5e3Sopenharmony_ci    NotationOption::ENGINEERING, NotationOption::COMPACT
564514f5e3Sopenharmony_ci};
574514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::NOTATION_OPTION_NAME = {
584514f5e3Sopenharmony_ci    "standard", "scientific", "engineering", "compact"
594514f5e3Sopenharmony_ci};
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ciconst std::vector<SignDisplayOption> JSNumberFormat::SIGN_DISPLAY_OPTION = {
624514f5e3Sopenharmony_ci    SignDisplayOption::AUTO, SignDisplayOption::NEVER,
634514f5e3Sopenharmony_ci    SignDisplayOption::ALWAYS, SignDisplayOption::EXCEPTZERO
644514f5e3Sopenharmony_ci};
654514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::SIGN_DISPLAY_OPTION_NAME = {
664514f5e3Sopenharmony_ci    "auto", "never", "always", "exceptZero"
674514f5e3Sopenharmony_ci};
684514f5e3Sopenharmony_ci
694514f5e3Sopenharmony_ciconst std::vector<CompactDisplayOption> JSNumberFormat::COMPACT_DISPLAY_OPTION = {
704514f5e3Sopenharmony_ci    CompactDisplayOption::SHORT, CompactDisplayOption::LONG
714514f5e3Sopenharmony_ci};
724514f5e3Sopenharmony_ciconst std::vector<std::string> JSNumberFormat::COMPACT_DISPLAY_OPTION_NAME = {"short", "long"};
734514f5e3Sopenharmony_ci
744514f5e3Sopenharmony_ciconst std::set<std::string> SANCTIONED_UNIT({ "acre", "bit", "byte", "celsius", "centimeter", "day", "degree",
754514f5e3Sopenharmony_ci                                            "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte",
764514f5e3Sopenharmony_ci                                            "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram",
774514f5e3Sopenharmony_ci                                            "kilometer", "liter", "megabit", "megabyte", "meter", "mile",
784514f5e3Sopenharmony_ci                                            "mile-scandinavian", "millimeter", "milliliter", "millisecond",
794514f5e3Sopenharmony_ci                                            "minute", "month", "ounce", "percent", "petabyte", "pound", "second",
804514f5e3Sopenharmony_ci                                            "stone", "terabit", "terabyte", "week", "yard", "year" });
814514f5e3Sopenharmony_ci
824514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, StyleOption style)
834514f5e3Sopenharmony_ci{
844514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
854514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
864514f5e3Sopenharmony_ci    switch (style) {
874514f5e3Sopenharmony_ci        case StyleOption::DECIMAL:
884514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledDecimalString().GetTaggedValue());
894514f5e3Sopenharmony_ci            break;
904514f5e3Sopenharmony_ci        case StyleOption::CURRENCY:
914514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledCurrencyString().GetTaggedValue());
924514f5e3Sopenharmony_ci            break;
934514f5e3Sopenharmony_ci        case StyleOption::PERCENT:
944514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledPercentString().GetTaggedValue());
954514f5e3Sopenharmony_ci            break;
964514f5e3Sopenharmony_ci        case StyleOption::UNIT:
974514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledUnitString().GetTaggedValue());
984514f5e3Sopenharmony_ci            break;
994514f5e3Sopenharmony_ci        default:
1004514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
1014514f5e3Sopenharmony_ci            UNREACHABLE();
1024514f5e3Sopenharmony_ci    }
1034514f5e3Sopenharmony_ci    return result;
1044514f5e3Sopenharmony_ci}
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, CurrencyDisplayOption currencyDisplay)
1074514f5e3Sopenharmony_ci{
1084514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
1094514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
1104514f5e3Sopenharmony_ci    switch (currencyDisplay) {
1114514f5e3Sopenharmony_ci        case CurrencyDisplayOption::CODE:
1124514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledCodeString().GetTaggedValue());
1134514f5e3Sopenharmony_ci            break;
1144514f5e3Sopenharmony_ci        case CurrencyDisplayOption::SYMBOL:
1154514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledSymbolString().GetTaggedValue());
1164514f5e3Sopenharmony_ci            break;
1174514f5e3Sopenharmony_ci        case CurrencyDisplayOption::NARROWSYMBOL:
1184514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledNarrowSymbolString().GetTaggedValue());
1194514f5e3Sopenharmony_ci            break;
1204514f5e3Sopenharmony_ci        case CurrencyDisplayOption::NAME:
1214514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledNameString().GetTaggedValue());
1224514f5e3Sopenharmony_ci            break;
1234514f5e3Sopenharmony_ci        default:
1244514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
1254514f5e3Sopenharmony_ci            UNREACHABLE();
1264514f5e3Sopenharmony_ci    }
1274514f5e3Sopenharmony_ci    return result;
1284514f5e3Sopenharmony_ci}
1294514f5e3Sopenharmony_ci
1304514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, CurrencySignOption currencySign)
1314514f5e3Sopenharmony_ci{
1324514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
1334514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
1344514f5e3Sopenharmony_ci    switch (currencySign) {
1354514f5e3Sopenharmony_ci        case CurrencySignOption::STANDARD:
1364514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledStandardString().GetTaggedValue());
1374514f5e3Sopenharmony_ci            break;
1384514f5e3Sopenharmony_ci        case CurrencySignOption::ACCOUNTING:
1394514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledAccountingString().GetTaggedValue());
1404514f5e3Sopenharmony_ci            break;
1414514f5e3Sopenharmony_ci        default:
1424514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
1434514f5e3Sopenharmony_ci            UNREACHABLE();
1444514f5e3Sopenharmony_ci    }
1454514f5e3Sopenharmony_ci    return result;
1464514f5e3Sopenharmony_ci}
1474514f5e3Sopenharmony_ci
1484514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, UnitDisplayOption unitDisplay)
1494514f5e3Sopenharmony_ci{
1504514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
1514514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
1524514f5e3Sopenharmony_ci    switch (unitDisplay) {
1534514f5e3Sopenharmony_ci        case UnitDisplayOption::SHORT:
1544514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledShortString().GetTaggedValue());
1554514f5e3Sopenharmony_ci            break;
1564514f5e3Sopenharmony_ci        case UnitDisplayOption::NARROW:
1574514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledNarrowString().GetTaggedValue());
1584514f5e3Sopenharmony_ci            break;
1594514f5e3Sopenharmony_ci        case UnitDisplayOption::LONG:
1604514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledLongString().GetTaggedValue());
1614514f5e3Sopenharmony_ci            break;
1624514f5e3Sopenharmony_ci        default:
1634514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
1644514f5e3Sopenharmony_ci            UNREACHABLE();
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci    return result;
1674514f5e3Sopenharmony_ci}
1684514f5e3Sopenharmony_ci
1694514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, NotationOption notation)
1704514f5e3Sopenharmony_ci{
1714514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
1724514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
1734514f5e3Sopenharmony_ci    switch (notation) {
1744514f5e3Sopenharmony_ci        case NotationOption::STANDARD:
1754514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledStandardString().GetTaggedValue());
1764514f5e3Sopenharmony_ci            break;
1774514f5e3Sopenharmony_ci        case NotationOption::SCIENTIFIC:
1784514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledScientificString().GetTaggedValue());
1794514f5e3Sopenharmony_ci            break;
1804514f5e3Sopenharmony_ci        case NotationOption::ENGINEERING:
1814514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledEngineeringString().GetTaggedValue());
1824514f5e3Sopenharmony_ci            break;
1834514f5e3Sopenharmony_ci        case NotationOption::COMPACT:
1844514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledCompactString().GetTaggedValue());
1854514f5e3Sopenharmony_ci            break;
1864514f5e3Sopenharmony_ci        default:
1874514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
1884514f5e3Sopenharmony_ci            UNREACHABLE();
1894514f5e3Sopenharmony_ci    }
1904514f5e3Sopenharmony_ci    return result;
1914514f5e3Sopenharmony_ci}
1924514f5e3Sopenharmony_ci
1934514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, CompactDisplayOption compactDisplay)
1944514f5e3Sopenharmony_ci{
1954514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
1964514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
1974514f5e3Sopenharmony_ci    switch (compactDisplay) {
1984514f5e3Sopenharmony_ci        case CompactDisplayOption::SHORT:
1994514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledShortString().GetTaggedValue());
2004514f5e3Sopenharmony_ci            break;
2014514f5e3Sopenharmony_ci        case CompactDisplayOption::LONG:
2024514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledLongString().GetTaggedValue());
2034514f5e3Sopenharmony_ci            break;
2044514f5e3Sopenharmony_ci        default:
2054514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
2064514f5e3Sopenharmony_ci            UNREACHABLE();
2074514f5e3Sopenharmony_ci    }
2084514f5e3Sopenharmony_ci    return result;
2094514f5e3Sopenharmony_ci}
2104514f5e3Sopenharmony_ci
2114514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> OptionToEcmaString(JSThread *thread, SignDisplayOption signDisplay)
2124514f5e3Sopenharmony_ci{
2134514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
2144514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
2154514f5e3Sopenharmony_ci    switch (signDisplay) {
2164514f5e3Sopenharmony_ci        case SignDisplayOption::AUTO:
2174514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledAutoString().GetTaggedValue());
2184514f5e3Sopenharmony_ci            break;
2194514f5e3Sopenharmony_ci        case SignDisplayOption::ALWAYS:
2204514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledAlwaysString().GetTaggedValue());
2214514f5e3Sopenharmony_ci            break;
2224514f5e3Sopenharmony_ci        case SignDisplayOption::NEVER:
2234514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledNeverString().GetTaggedValue());
2244514f5e3Sopenharmony_ci            break;
2254514f5e3Sopenharmony_ci        case SignDisplayOption::EXCEPTZERO:
2264514f5e3Sopenharmony_ci            result.Update(globalConst->GetHandledExceptZeroString().GetTaggedValue());
2274514f5e3Sopenharmony_ci            break;
2284514f5e3Sopenharmony_ci        default:
2294514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
2304514f5e3Sopenharmony_ci            UNREACHABLE();
2314514f5e3Sopenharmony_ci    }
2324514f5e3Sopenharmony_ci    return result;
2334514f5e3Sopenharmony_ci}
2344514f5e3Sopenharmony_ci
2354514f5e3Sopenharmony_ciicu::MeasureUnit ToMeasureUnit(const std::string &sanctionedUnit)
2364514f5e3Sopenharmony_ci{
2374514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
2384514f5e3Sopenharmony_ci    // Get All ICU measure unit
2394514f5e3Sopenharmony_ci    int32_t total = icu::MeasureUnit::getAvailable(nullptr, 0, status);
2404514f5e3Sopenharmony_ci    status = U_ZERO_ERROR;
2414514f5e3Sopenharmony_ci    std::vector<icu::MeasureUnit> units(total);
2424514f5e3Sopenharmony_ci    icu::MeasureUnit::getAvailable(units.data(), total, status);
2434514f5e3Sopenharmony_ci    ASSERT(U_SUCCESS(status));
2444514f5e3Sopenharmony_ci
2454514f5e3Sopenharmony_ci    // Find measure unit according to sanctioned unit
2464514f5e3Sopenharmony_ci    //  then return measure unit
2474514f5e3Sopenharmony_ci    for (auto &unit : units) {
2484514f5e3Sopenharmony_ci        if (std::strcmp(sanctionedUnit.c_str(), unit.getSubtype()) == 0) {
2494514f5e3Sopenharmony_ci            return unit;
2504514f5e3Sopenharmony_ci        }
2514514f5e3Sopenharmony_ci    }
2524514f5e3Sopenharmony_ci    return icu::MeasureUnit();
2534514f5e3Sopenharmony_ci}
2544514f5e3Sopenharmony_ci
2554514f5e3Sopenharmony_ci// ecma402 #sec-issanctionedsimpleunitidentifier
2564514f5e3Sopenharmony_cibool IsSanctionedSimpleUnitIdentifier(const std::string &unit)
2574514f5e3Sopenharmony_ci{
2584514f5e3Sopenharmony_ci    // 1. If unitIdentifier is listed in sanctioned unit set, return true.
2594514f5e3Sopenharmony_ci    auto it = SANCTIONED_UNIT.find(unit);
2604514f5e3Sopenharmony_ci    if (it != SANCTIONED_UNIT.end()) {
2614514f5e3Sopenharmony_ci        return true;
2624514f5e3Sopenharmony_ci    }
2634514f5e3Sopenharmony_ci
2644514f5e3Sopenharmony_ci    // 2. Else, Return false.
2654514f5e3Sopenharmony_ci    return false;
2664514f5e3Sopenharmony_ci}
2674514f5e3Sopenharmony_ci
2684514f5e3Sopenharmony_ci// 6.5.1 IsWellFormedUnitIdentifier ( unitIdentifier )
2694514f5e3Sopenharmony_cibool IsWellFormedUnitIdentifier(const std::string &unit, icu::MeasureUnit &icuUnit, icu::MeasureUnit &icuPerUnit)
2704514f5e3Sopenharmony_ci{
2714514f5e3Sopenharmony_ci    // 1. If the result of IsSanctionedSimpleUnitIdentifier(unitIdentifier) is true, then
2724514f5e3Sopenharmony_ci    //      a. Return true.
2734514f5e3Sopenharmony_ci    icu::MeasureUnit result = icu::MeasureUnit();
2744514f5e3Sopenharmony_ci    icu::MeasureUnit emptyUnit = icu::MeasureUnit();
2754514f5e3Sopenharmony_ci    auto pos = unit.find("-per-");
2764514f5e3Sopenharmony_ci    if (IsSanctionedSimpleUnitIdentifier(unit) && pos == std::string::npos) {
2774514f5e3Sopenharmony_ci        result = ToMeasureUnit(unit);
2784514f5e3Sopenharmony_ci        icuUnit = result;
2794514f5e3Sopenharmony_ci        icuPerUnit = emptyUnit;
2804514f5e3Sopenharmony_ci        return true;
2814514f5e3Sopenharmony_ci    }
2824514f5e3Sopenharmony_ci
2834514f5e3Sopenharmony_ci    // 2. If the substring "-per-" does not occur exactly once in unitIdentifier,
2844514f5e3Sopenharmony_ci    //      a. then false
2854514f5e3Sopenharmony_ci    size_t afterPos = pos + JSNumberFormat::PERUNIT_STRING;
2864514f5e3Sopenharmony_ci    if (pos == std::string::npos || unit.find("-per-", afterPos) != std::string::npos) {
2874514f5e3Sopenharmony_ci        return false;
2884514f5e3Sopenharmony_ci    }
2894514f5e3Sopenharmony_ci
2904514f5e3Sopenharmony_ci    // 3. Let numerator be the substring of unitIdentifier from the beginning to just before "-per-".
2914514f5e3Sopenharmony_ci    std::string numerator = unit.substr(0, pos);
2924514f5e3Sopenharmony_ci    // 4. If the result of IsSanctionedUnitIdentifier(numerator) is false, then
2934514f5e3Sopenharmony_ci    //      a. return false
2944514f5e3Sopenharmony_ci    if (IsSanctionedSimpleUnitIdentifier(numerator)) {
2954514f5e3Sopenharmony_ci        result = ToMeasureUnit(numerator);
2964514f5e3Sopenharmony_ci    } else {
2974514f5e3Sopenharmony_ci        return false;
2984514f5e3Sopenharmony_ci    }
2994514f5e3Sopenharmony_ci
3004514f5e3Sopenharmony_ci    // 5. Let denominator be the substring of unitIdentifier from just after "-per-" to the end.
3014514f5e3Sopenharmony_ci    std::string denominator = unit.substr(pos + JSNumberFormat::PERUNIT_STRING);
3024514f5e3Sopenharmony_ci
3034514f5e3Sopenharmony_ci    // 6. If the result of IsSanctionedUnitIdentifier(denominator) is false, then
3044514f5e3Sopenharmony_ci    //      a. Return false
3054514f5e3Sopenharmony_ci    icu::MeasureUnit perResult = icu::MeasureUnit();
3064514f5e3Sopenharmony_ci    if (IsSanctionedSimpleUnitIdentifier(denominator)) {
3074514f5e3Sopenharmony_ci        perResult = ToMeasureUnit(denominator);
3084514f5e3Sopenharmony_ci    } else {
3094514f5e3Sopenharmony_ci        return false;
3104514f5e3Sopenharmony_ci    }
3114514f5e3Sopenharmony_ci
3124514f5e3Sopenharmony_ci    // 7. Return true.
3134514f5e3Sopenharmony_ci    icuUnit = result;
3144514f5e3Sopenharmony_ci    icuPerUnit = perResult;
3154514f5e3Sopenharmony_ci    return true;
3164514f5e3Sopenharmony_ci}
3174514f5e3Sopenharmony_ci
3184514f5e3Sopenharmony_ci// 12.1.13 SetNumberFormatUnitOptions ( intlObj, options )
3194514f5e3Sopenharmony_ciFractionDigitsOption SetNumberFormatUnitOptions(JSThread *thread,
3204514f5e3Sopenharmony_ci                                                const JSHandle<JSNumberFormat> &numberFormat,
3214514f5e3Sopenharmony_ci                                                const JSHandle<JSObject> &optionsObject,
3224514f5e3Sopenharmony_ci                                                icu::number::LocalizedNumberFormatter *icuNumberFormatter)
3234514f5e3Sopenharmony_ci{
3244514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
3254514f5e3Sopenharmony_ci    FractionDigitsOption fractionDigitsOption;
3264514f5e3Sopenharmony_ci    // 3. Let style be ? GetOption(options, "style", "string", « "decimal", "percent", "currency", "unit" », "decimal").
3274514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> property = globalConst->GetHandledStyleString();
3284514f5e3Sopenharmony_ci    auto style = JSLocale::GetOptionOfString<StyleOption>(
3294514f5e3Sopenharmony_ci        thread, optionsObject, property,
3304514f5e3Sopenharmony_ci        JSNumberFormat::STYLE_OPTION, JSNumberFormat::STYLE_OPTION_NAME,
3314514f5e3Sopenharmony_ci        StyleOption::DECIMAL);
3324514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption);
3334514f5e3Sopenharmony_ci
3344514f5e3Sopenharmony_ci    // 4. Set intlObj.[[Style]] to style.
3354514f5e3Sopenharmony_ci    numberFormat->SetStyle(style);
3364514f5e3Sopenharmony_ci
3374514f5e3Sopenharmony_ci    // 5. Let currency be ? GetOption(options, "currency", "string", undefined, undefined).
3384514f5e3Sopenharmony_ci    property = globalConst->GetHandledCurrencyString();
3394514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined());
3404514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> currency =
3414514f5e3Sopenharmony_ci        JSLocale::GetOption(thread, optionsObject, property, OptionType::STRING, undefinedValue, undefinedValue);
3424514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption);
3434514f5e3Sopenharmony_ci
3444514f5e3Sopenharmony_ci    // 6. If currency is not undefined, then
3454514f5e3Sopenharmony_ci    //    a. If the result of IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
3464514f5e3Sopenharmony_ci    if (!currency->IsUndefined()) {
3474514f5e3Sopenharmony_ci        JSHandle<EcmaString> currencyStr = JSHandle<EcmaString>::Cast(currency);
3484514f5e3Sopenharmony_ci        if (EcmaStringAccessor(currencyStr).IsUtf16()) {
3494514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "not a utf-8", fractionDigitsOption);
3504514f5e3Sopenharmony_ci        }
3514514f5e3Sopenharmony_ci        std::string currencyCStr = intl::LocaleHelper::ConvertToStdString(currencyStr);
3524514f5e3Sopenharmony_ci        if (!JSLocale::IsWellFormedCurrencyCode(currencyCStr)) {
3534514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "not a wellformed code", fractionDigitsOption);
3544514f5e3Sopenharmony_ci        }
3554514f5e3Sopenharmony_ci    } else {
3564514f5e3Sopenharmony_ci        // 7. If style is "currency" and currency is undefined, throw a TypeError exception.
3574514f5e3Sopenharmony_ci        if (style == StyleOption::CURRENCY) {
3584514f5e3Sopenharmony_ci            THROW_TYPE_ERROR_AND_RETURN(thread, "style is currency but currency is undefined", fractionDigitsOption);
3594514f5e3Sopenharmony_ci        }
3604514f5e3Sopenharmony_ci    }
3614514f5e3Sopenharmony_ci
3624514f5e3Sopenharmony_ci    // 8. Let currencyDisplay be ? GetOption(options, "currencyDisplay", "string",
3634514f5e3Sopenharmony_ci    //  « "code", "symbol", "narrowSymbol", "name" », "symbol").
3644514f5e3Sopenharmony_ci    property = globalConst->GetHandledCurrencyDisplayString();
3654514f5e3Sopenharmony_ci    auto currencyDisplay = JSLocale::GetOptionOfString<CurrencyDisplayOption>(
3664514f5e3Sopenharmony_ci        thread, optionsObject, property,
3674514f5e3Sopenharmony_ci        JSNumberFormat::CURRENCY_DISPLAY_OPTION, JSNumberFormat::CURRENCY_DISPLAY_OPTION_NAME,
3684514f5e3Sopenharmony_ci        CurrencyDisplayOption::SYMBOL);
3694514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption);
3704514f5e3Sopenharmony_ci    numberFormat->SetCurrencyDisplay(currencyDisplay);
3714514f5e3Sopenharmony_ci
3724514f5e3Sopenharmony_ci    // 9. Let currencySign be ? GetOption(options, "currencySign", "string", « "standard", "accounting" », "standard").
3734514f5e3Sopenharmony_ci    property = globalConst->GetHandledCurrencySignString();
3744514f5e3Sopenharmony_ci    auto currencySign = JSLocale::GetOptionOfString<CurrencySignOption>(
3754514f5e3Sopenharmony_ci        thread, optionsObject, property,
3764514f5e3Sopenharmony_ci        JSNumberFormat::CURRENCY_SIGN_OPTION, JSNumberFormat::CURRENCY_SIGN_OPTION_NAME,
3774514f5e3Sopenharmony_ci        CurrencySignOption::STANDARD);
3784514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption);
3794514f5e3Sopenharmony_ci    numberFormat->SetCurrencySign(currencySign);
3804514f5e3Sopenharmony_ci
3814514f5e3Sopenharmony_ci    // 10. Let unit be ? GetOption(options, "unit", "string", undefined, undefined).
3824514f5e3Sopenharmony_ci    property = globalConst->GetHandledUnitString();
3834514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> unit =
3844514f5e3Sopenharmony_ci        JSLocale::GetOption(thread, optionsObject, property, OptionType::STRING, undefinedValue, undefinedValue);
3854514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption);
3864514f5e3Sopenharmony_ci    numberFormat->SetUnit(thread, unit);
3874514f5e3Sopenharmony_ci
3884514f5e3Sopenharmony_ci    // 11. If unit is not undefined, then
3894514f5e3Sopenharmony_ci    // If the result of IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
3904514f5e3Sopenharmony_ci    icu::MeasureUnit icuUnit;
3914514f5e3Sopenharmony_ci    icu::MeasureUnit icuPerUnit;
3924514f5e3Sopenharmony_ci    if (!unit->IsUndefined()) {
3934514f5e3Sopenharmony_ci        JSHandle<EcmaString> unitStr = JSHandle<EcmaString>::Cast(unit);
3944514f5e3Sopenharmony_ci        if (EcmaStringAccessor(unitStr).IsUtf16()) {
3954514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "Unit input is illegal", fractionDigitsOption);
3964514f5e3Sopenharmony_ci        }
3974514f5e3Sopenharmony_ci        std::string str = intl::LocaleHelper::ConvertToStdString(unitStr);
3984514f5e3Sopenharmony_ci        if (!IsWellFormedUnitIdentifier(str, icuUnit, icuPerUnit)) {
3994514f5e3Sopenharmony_ci            THROW_RANGE_ERROR_AND_RETURN(thread, "Unit input is illegal", fractionDigitsOption);
4004514f5e3Sopenharmony_ci        }
4014514f5e3Sopenharmony_ci    } else {
4024514f5e3Sopenharmony_ci        // 15.12. if style is "unit" and unit is undefined, throw a TypeError exception.
4034514f5e3Sopenharmony_ci        if (style == StyleOption::UNIT) {
4044514f5e3Sopenharmony_ci            THROW_TYPE_ERROR_AND_RETURN(thread, "style is unit but unit is undefined", fractionDigitsOption);
4054514f5e3Sopenharmony_ci        }
4064514f5e3Sopenharmony_ci    }
4074514f5e3Sopenharmony_ci
4084514f5e3Sopenharmony_ci    // 13. Let unitDisplay be ? GetOption(options, "unitDisplay", "string", « "short", "narrow", "long" », "short").
4094514f5e3Sopenharmony_ci    property = globalConst->GetHandledUnitDisplayString();
4104514f5e3Sopenharmony_ci    auto unitDisplay = JSLocale::GetOptionOfString<UnitDisplayOption>(
4114514f5e3Sopenharmony_ci        thread, optionsObject, property,
4124514f5e3Sopenharmony_ci        JSNumberFormat::UNIT_DISPLAY_OPTION, JSNumberFormat::UNIT_DISPLAY_OPTION_NAME,
4134514f5e3Sopenharmony_ci        UnitDisplayOption::SHORT);
4144514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, fractionDigitsOption);
4154514f5e3Sopenharmony_ci    numberFormat->SetUnitDisplay(unitDisplay);
4164514f5e3Sopenharmony_ci
4174514f5e3Sopenharmony_ci    // 14. If style is "currency", then
4184514f5e3Sopenharmony_ci    //      a. Let currency be the result of converting currency to upper case as specified in 6.1.
4194514f5e3Sopenharmony_ci    //      b. Set intlObj.[[Currency]] to currency.
4204514f5e3Sopenharmony_ci    //      c. Set intlObj.[[CurrencyDisplay]] to currencyDisplay.
4214514f5e3Sopenharmony_ci    //      d. Set intlObj.[[CurrencySign]] to currencySign.
4224514f5e3Sopenharmony_ci    icu::UnicodeString currencyUStr;
4234514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
4244514f5e3Sopenharmony_ci    if (style == StyleOption::CURRENCY) {
4254514f5e3Sopenharmony_ci        JSHandle<EcmaString> currencyStr = JSHandle<EcmaString>::Cast(currency);
4264514f5e3Sopenharmony_ci        std::string currencyCStr = intl::LocaleHelper::ConvertToStdString(currencyStr);
4274514f5e3Sopenharmony_ci        std::transform(currencyCStr.begin(), currencyCStr.end(), currencyCStr.begin(), toupper);
4284514f5e3Sopenharmony_ci        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
4294514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> currencyValue = JSHandle<JSTaggedValue>::Cast(factory->NewFromStdString(currencyCStr));
4304514f5e3Sopenharmony_ci        numberFormat->SetCurrency(thread, currencyValue);
4314514f5e3Sopenharmony_ci        currencyUStr = currencyCStr.c_str();
4324514f5e3Sopenharmony_ci        if (!currencyUStr.isEmpty()) {  // NOLINT(readability-implicit-bool-conversion)
4334514f5e3Sopenharmony_ci            *icuNumberFormatter = icuNumberFormatter->unit(icu::CurrencyUnit(currencyUStr.getBuffer(), status));
4344514f5e3Sopenharmony_ci            ASSERT(U_SUCCESS(status));
4354514f5e3Sopenharmony_ci            UNumberUnitWidth uNumberUnitWidth;
4364514f5e3Sopenharmony_ci            // Trans currencyDisplayOption to ICU format number display option
4374514f5e3Sopenharmony_ci            switch (currencyDisplay) {
4384514f5e3Sopenharmony_ci                case CurrencyDisplayOption::CODE:
4394514f5e3Sopenharmony_ci                    uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE;
4404514f5e3Sopenharmony_ci                    break;
4414514f5e3Sopenharmony_ci                case CurrencyDisplayOption::SYMBOL:
4424514f5e3Sopenharmony_ci                    uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT;
4434514f5e3Sopenharmony_ci                    break;
4444514f5e3Sopenharmony_ci                case CurrencyDisplayOption::NARROWSYMBOL:
4454514f5e3Sopenharmony_ci                    uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW;
4464514f5e3Sopenharmony_ci                    break;
4474514f5e3Sopenharmony_ci                case CurrencyDisplayOption::NAME:
4484514f5e3Sopenharmony_ci                    uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME;
4494514f5e3Sopenharmony_ci                    break;
4504514f5e3Sopenharmony_ci                default:
4514514f5e3Sopenharmony_ci                    LOG_ECMA(FATAL) << "this branch is unreachable";
4524514f5e3Sopenharmony_ci                    UNREACHABLE();
4534514f5e3Sopenharmony_ci            }
4544514f5e3Sopenharmony_ci            *icuNumberFormatter = icuNumberFormatter->unitWidth(uNumberUnitWidth);
4554514f5e3Sopenharmony_ci        }
4564514f5e3Sopenharmony_ci    }
4574514f5e3Sopenharmony_ci
4584514f5e3Sopenharmony_ci    // 15. If style is "unit", then
4594514f5e3Sopenharmony_ci    // if unit is not undefiend set unit to LocalizedNumberFormatter
4604514f5e3Sopenharmony_ci    //    then if perunit is not undefiend set perunit to LocalizedNumberFormatter
4614514f5e3Sopenharmony_ci    if (style == StyleOption::UNIT) {
4624514f5e3Sopenharmony_ci        icu::MeasureUnit emptyUnit = icu::MeasureUnit();
4634514f5e3Sopenharmony_ci        if (icuUnit != emptyUnit) {  // NOLINT(readability-implicit-bool-conversion)
4644514f5e3Sopenharmony_ci            *icuNumberFormatter = icuNumberFormatter->unit(icuUnit);
4654514f5e3Sopenharmony_ci        }
4664514f5e3Sopenharmony_ci        if (icuPerUnit != emptyUnit) {  // NOLINT(readability-implicit-bool-conversion)
4674514f5e3Sopenharmony_ci            *icuNumberFormatter = icuNumberFormatter->perUnit(icuPerUnit);
4684514f5e3Sopenharmony_ci        }
4694514f5e3Sopenharmony_ci    }
4704514f5e3Sopenharmony_ci
4714514f5e3Sopenharmony_ci    // 17. If style is "currency", then
4724514f5e3Sopenharmony_ci    //      a. Let cDigits be CurrencyDigits(currency).
4734514f5e3Sopenharmony_ci    //      b. Let mnfdDefault be cDigits.
4744514f5e3Sopenharmony_ci    //      c. Let mxfdDefault be cDigits.
4754514f5e3Sopenharmony_ci    if (style == StyleOption::CURRENCY) {
4764514f5e3Sopenharmony_ci        int32_t cDigits = JSNumberFormat::CurrencyDigits(currencyUStr);
4774514f5e3Sopenharmony_ci        fractionDigitsOption.mnfdDefault = cDigits;
4784514f5e3Sopenharmony_ci        fractionDigitsOption.mxfdDefault = cDigits;
4794514f5e3Sopenharmony_ci    } else {
4804514f5e3Sopenharmony_ci        // 18. Else,
4814514f5e3Sopenharmony_ci        //      a. Let mnfdDefault be 0.
4824514f5e3Sopenharmony_ci        //      b. If style is "percent", then
4834514f5e3Sopenharmony_ci        //          i. Let mxfdDefault be 0.
4844514f5e3Sopenharmony_ci        //      c. else,
4854514f5e3Sopenharmony_ci        //          i. Let mxfdDefault be 3.
4864514f5e3Sopenharmony_ci        fractionDigitsOption.mnfdDefault = 0;
4874514f5e3Sopenharmony_ci        if (style == StyleOption::PERCENT) {
4884514f5e3Sopenharmony_ci            fractionDigitsOption.mxfdDefault = 0;
4894514f5e3Sopenharmony_ci        } else {
4904514f5e3Sopenharmony_ci            fractionDigitsOption.mxfdDefault = 3;  // Max decimal precision is 3
4914514f5e3Sopenharmony_ci        }
4924514f5e3Sopenharmony_ci    }
4934514f5e3Sopenharmony_ci    return fractionDigitsOption;
4944514f5e3Sopenharmony_ci}
4954514f5e3Sopenharmony_ci
4964514f5e3Sopenharmony_ci// 12.1.2 InitializeNumberFormat ( numberFormat, locales, options )
4974514f5e3Sopenharmony_ci// NOLINTNEXTLINE(readability-function-size)
4984514f5e3Sopenharmony_civoid JSNumberFormat::InitializeNumberFormat(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat,
4994514f5e3Sopenharmony_ci                                            const JSHandle<JSTaggedValue> &locales,
5004514f5e3Sopenharmony_ci                                            const JSHandle<JSTaggedValue> &options,
5014514f5e3Sopenharmony_ci                                            bool forIcuCache)
5024514f5e3Sopenharmony_ci{
5034514f5e3Sopenharmony_ci    EcmaVM *ecmaVm = thread->GetEcmaVM();
5044514f5e3Sopenharmony_ci    ObjectFactory *factory = ecmaVm->GetFactory();
5054514f5e3Sopenharmony_ci    // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
5064514f5e3Sopenharmony_ci    JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales);
5074514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
5084514f5e3Sopenharmony_ci    // 2. If options is undefined, then
5094514f5e3Sopenharmony_ci    //      a. Let options be ObjectCreate(null).
5104514f5e3Sopenharmony_ci    // 3. Else,
5114514f5e3Sopenharmony_ci    //      a. Let options be ? ToObject(options).
5124514f5e3Sopenharmony_ci    JSHandle<JSObject> optionsObject;
5134514f5e3Sopenharmony_ci    if (options->IsUndefined()) {
5144514f5e3Sopenharmony_ci        optionsObject = factory->CreateNullJSObject();
5154514f5e3Sopenharmony_ci    } else {
5164514f5e3Sopenharmony_ci        optionsObject = JSTaggedValue::ToObject(thread, options);
5174514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
5184514f5e3Sopenharmony_ci    }
5194514f5e3Sopenharmony_ci
5204514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
5214514f5e3Sopenharmony_ci    // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
5224514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleMatcherString();
5234514f5e3Sopenharmony_ci    auto matcher = JSLocale::GetOptionOfString<LocaleMatcherOption>(
5244514f5e3Sopenharmony_ci        thread, optionsObject, property,
5254514f5e3Sopenharmony_ci        JSNumberFormat::LOCALE_MATCHER_OPTION, JSNumberFormat::LOCALE_MATCHER_OPTION_NAME,
5264514f5e3Sopenharmony_ci        LocaleMatcherOption::BEST_FIT);
5274514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
5284514f5e3Sopenharmony_ci
5294514f5e3Sopenharmony_ci    // 7. Let numberingSystem be ? GetOption(options, "numberingSystem", "string", undefined, undefined).
5304514f5e3Sopenharmony_ci    property = globalConst->GetHandledNumberingSystemString();
5314514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined());
5324514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> numberingSystemTaggedValue =
5334514f5e3Sopenharmony_ci        JSLocale::GetOption(thread, optionsObject, property, OptionType::STRING, undefinedValue, undefinedValue);
5344514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
5354514f5e3Sopenharmony_ci    numberFormat->SetNumberingSystem(thread, numberingSystemTaggedValue);
5364514f5e3Sopenharmony_ci
5374514f5e3Sopenharmony_ci    // 8. If numberingSystem is not undefined, then
5384514f5e3Sopenharmony_ci    //      a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal,
5394514f5e3Sopenharmony_ci    //      throw a RangeError exception. `(3*8alphanum) *("-" (3*8alphanum))`
5404514f5e3Sopenharmony_ci    std::string numberingSystemStr;
5414514f5e3Sopenharmony_ci    if (!numberingSystemTaggedValue->IsUndefined()) {
5424514f5e3Sopenharmony_ci        JSHandle<EcmaString> numberingSystemEcmaString = JSHandle<EcmaString>::Cast(numberingSystemTaggedValue);
5434514f5e3Sopenharmony_ci        if (EcmaStringAccessor(numberingSystemEcmaString).IsUtf16()) {
5444514f5e3Sopenharmony_ci            THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem");
5454514f5e3Sopenharmony_ci        }
5464514f5e3Sopenharmony_ci        numberingSystemStr = intl::LocaleHelper::ConvertToStdString(numberingSystemEcmaString);
5474514f5e3Sopenharmony_ci        if (!JSLocale::IsNormativeNumberingSystem(numberingSystemStr)) {
5484514f5e3Sopenharmony_ci            THROW_ERROR(thread, ErrorType::RANGE_ERROR, "invalid numberingSystem");
5494514f5e3Sopenharmony_ci        }
5504514f5e3Sopenharmony_ci    }
5514514f5e3Sopenharmony_ci
5524514f5e3Sopenharmony_ci    if (!numberingSystemStr.empty()) {
5534514f5e3Sopenharmony_ci        // If numberingSystem is invalid, Let numberingSystem be undefined.
5544514f5e3Sopenharmony_ci        if (!JSLocale::IsWellNumberingSystem(numberingSystemStr)) {
5554514f5e3Sopenharmony_ci            numberFormat->SetNumberingSystem(thread, undefinedValue);
5564514f5e3Sopenharmony_ci        }
5574514f5e3Sopenharmony_ci    }
5584514f5e3Sopenharmony_ci
5594514f5e3Sopenharmony_ci    // 10. Let localeData be %NumberFormat%.[[LocaleData]].
5604514f5e3Sopenharmony_ci    JSHandle<TaggedArray> availableLocales;
5614514f5e3Sopenharmony_ci    if (requestedLocales->GetLength() == 0) {
5624514f5e3Sopenharmony_ci        availableLocales = factory->EmptyArray();
5634514f5e3Sopenharmony_ci    } else {
5644514f5e3Sopenharmony_ci        availableLocales = GetAvailableLocales(thread);
5654514f5e3Sopenharmony_ci    }
5664514f5e3Sopenharmony_ci
5674514f5e3Sopenharmony_ci    // 11. Let r be ResolveLocale( %NumberFormat%.[[AvailableLocales]], requestedLocales, opt,
5684514f5e3Sopenharmony_ci    // %NumberFormat%.[[RelevantExtensionKeys]], localeData).
5694514f5e3Sopenharmony_ci    std::set<std::string> relevantExtensionKeys{"nu"};
5704514f5e3Sopenharmony_ci    ResolvedLocale r =
5714514f5e3Sopenharmony_ci        JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys);
5724514f5e3Sopenharmony_ci
5734514f5e3Sopenharmony_ci    // 12. Set numberFormat.[[Locale]] to r.[[locale]].
5744514f5e3Sopenharmony_ci    icu::Locale icuLocale = r.localeData;
5754514f5e3Sopenharmony_ci    JSHandle<EcmaString> localeStr = intl::LocaleHelper::ToLanguageTag(thread, icuLocale);
5764514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
5774514f5e3Sopenharmony_ci    numberFormat->SetLocale(thread, localeStr.GetTaggedValue());
5784514f5e3Sopenharmony_ci
5794514f5e3Sopenharmony_ci    // Set numberingSystemStr to UnicodeKeyWord "nu"
5804514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
5814514f5e3Sopenharmony_ci    if (!numberingSystemStr.empty()) {
5824514f5e3Sopenharmony_ci        if (JSLocale::IsWellNumberingSystem(numberingSystemStr)) {
5834514f5e3Sopenharmony_ci            icuLocale.setUnicodeKeywordValue("nu", numberingSystemStr, status);
5844514f5e3Sopenharmony_ci            ASSERT(U_SUCCESS(status));
5854514f5e3Sopenharmony_ci        }
5864514f5e3Sopenharmony_ci    }
5874514f5e3Sopenharmony_ci
5884514f5e3Sopenharmony_ci    icu::number::LocalizedNumberFormatter icuNumberFormatter =
5894514f5e3Sopenharmony_ci        icu::number::NumberFormatter::withLocale(icuLocale).roundingMode(UNUM_ROUND_HALFUP);
5904514f5e3Sopenharmony_ci
5914514f5e3Sopenharmony_ci    int32_t mnfdDefault = 0;
5924514f5e3Sopenharmony_ci    int32_t mxfdDefault = 0;
5934514f5e3Sopenharmony_ci    FractionDigitsOption fractionOptions =
5944514f5e3Sopenharmony_ci        SetNumberFormatUnitOptions(thread, numberFormat, optionsObject, &icuNumberFormatter);
5954514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
5964514f5e3Sopenharmony_ci    mnfdDefault = fractionOptions.mnfdDefault;
5974514f5e3Sopenharmony_ci    mxfdDefault = fractionOptions.mxfdDefault;
5984514f5e3Sopenharmony_ci    UnitDisplayOption unitDisplay = numberFormat->GetUnitDisplay();
5994514f5e3Sopenharmony_ci
6004514f5e3Sopenharmony_ci    // Trans unitDisplay option to ICU display option
6014514f5e3Sopenharmony_ci    UNumberUnitWidth uNumberUnitWidth;
6024514f5e3Sopenharmony_ci    switch (unitDisplay) {
6034514f5e3Sopenharmony_ci        case UnitDisplayOption::SHORT:
6044514f5e3Sopenharmony_ci            uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT;
6054514f5e3Sopenharmony_ci            break;
6064514f5e3Sopenharmony_ci        case UnitDisplayOption::NARROW:
6074514f5e3Sopenharmony_ci            uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW;
6084514f5e3Sopenharmony_ci            break;
6094514f5e3Sopenharmony_ci        case UnitDisplayOption::LONG:
6104514f5e3Sopenharmony_ci            // UNUM_UNIT_WIDTH_FULL_NAME Print the full name of the unit, without any abbreviations.
6114514f5e3Sopenharmony_ci            uNumberUnitWidth = UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME;
6124514f5e3Sopenharmony_ci            break;
6134514f5e3Sopenharmony_ci        default:
6144514f5e3Sopenharmony_ci            LOG_ECMA(FATAL) << "this branch is unreachable";
6154514f5e3Sopenharmony_ci            UNREACHABLE();
6164514f5e3Sopenharmony_ci    }
6174514f5e3Sopenharmony_ci    icuNumberFormatter = icuNumberFormatter.unitWidth(uNumberUnitWidth);
6184514f5e3Sopenharmony_ci
6194514f5e3Sopenharmony_ci    // 16. Let style be numberFormat.[[Style]].
6204514f5e3Sopenharmony_ci    StyleOption style = numberFormat->GetStyle();
6214514f5e3Sopenharmony_ci    if (style == StyleOption::PERCENT) {
6224514f5e3Sopenharmony_ci        icuNumberFormatter = icuNumberFormatter.unit(icu::MeasureUnit::getPercent()).
6234514f5e3Sopenharmony_ci            scale(icu::number::Scale::powerOfTen(2));  // means 10^2
6244514f5e3Sopenharmony_ci    }
6254514f5e3Sopenharmony_ci
6264514f5e3Sopenharmony_ci    // 19. Let notation be ? GetOption(
6274514f5e3Sopenharmony_ci    //  options, "notation", "string", « "standard", "scientific", "engineering", "compact" », "standard").
6284514f5e3Sopenharmony_ci    property = globalConst->GetHandledNotationString();
6294514f5e3Sopenharmony_ci    auto notation = JSLocale::GetOptionOfString<NotationOption>(
6304514f5e3Sopenharmony_ci        thread, optionsObject, property,
6314514f5e3Sopenharmony_ci        JSNumberFormat::NOTATION_OPTION, JSNumberFormat::NOTATION_OPTION_NAME,
6324514f5e3Sopenharmony_ci        NotationOption::STANDARD);
6334514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
6344514f5e3Sopenharmony_ci    numberFormat->SetNotation(notation);
6354514f5e3Sopenharmony_ci
6364514f5e3Sopenharmony_ci    // 21. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
6374514f5e3Sopenharmony_ci    JSLocale::SetNumberFormatDigitOptions(thread, numberFormat, JSHandle<JSTaggedValue>::Cast(optionsObject),
6384514f5e3Sopenharmony_ci                                          mnfdDefault, mxfdDefault, notation);
6394514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
6404514f5e3Sopenharmony_ci    icuNumberFormatter = SetICUFormatterDigitOptions(icuNumberFormatter, numberFormat);
6414514f5e3Sopenharmony_ci
6424514f5e3Sopenharmony_ci    // 22. Let compactDisplay be ? GetOptionOfString(options, "compactDisplay", "string", « "short", "long" », "short").
6434514f5e3Sopenharmony_ci    property = globalConst->GetHandledCompactDisplayString();
6444514f5e3Sopenharmony_ci    auto compactDisplay = JSLocale::GetOptionOfString<CompactDisplayOption>(
6454514f5e3Sopenharmony_ci        thread, optionsObject, property,
6464514f5e3Sopenharmony_ci        JSNumberFormat::COMPACT_DISPLAY_OPTION, JSNumberFormat::COMPACT_DISPLAY_OPTION_NAME,
6474514f5e3Sopenharmony_ci        CompactDisplayOption::SHORT);
6484514f5e3Sopenharmony_ci    numberFormat->SetCompactDisplay(compactDisplay);
6494514f5e3Sopenharmony_ci
6504514f5e3Sopenharmony_ci    // Trans NotationOption to ICU Noation and set to icuNumberFormatter
6514514f5e3Sopenharmony_ci    if (notation == NotationOption::COMPACT) {
6524514f5e3Sopenharmony_ci        switch (compactDisplay) {
6534514f5e3Sopenharmony_ci            case CompactDisplayOption::SHORT:
6544514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::compactShort());
6554514f5e3Sopenharmony_ci                break;
6564514f5e3Sopenharmony_ci            case CompactDisplayOption::LONG:
6574514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::compactLong());
6584514f5e3Sopenharmony_ci                break;
6594514f5e3Sopenharmony_ci            default:
6604514f5e3Sopenharmony_ci                break;
6614514f5e3Sopenharmony_ci        }
6624514f5e3Sopenharmony_ci    }
6634514f5e3Sopenharmony_ci    switch (notation) {
6644514f5e3Sopenharmony_ci        case NotationOption::STANDARD:
6654514f5e3Sopenharmony_ci            icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::simple());
6664514f5e3Sopenharmony_ci            break;
6674514f5e3Sopenharmony_ci        case NotationOption::SCIENTIFIC:
6684514f5e3Sopenharmony_ci            icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::scientific());
6694514f5e3Sopenharmony_ci            break;
6704514f5e3Sopenharmony_ci        case NotationOption::ENGINEERING:
6714514f5e3Sopenharmony_ci            icuNumberFormatter = icuNumberFormatter.notation(icu::number::Notation::engineering());
6724514f5e3Sopenharmony_ci            break;
6734514f5e3Sopenharmony_ci        default:
6744514f5e3Sopenharmony_ci            break;
6754514f5e3Sopenharmony_ci    }
6764514f5e3Sopenharmony_ci
6774514f5e3Sopenharmony_ci    // 24. Let useGrouping be ? GetOption(options, "useGrouping", "boolean", undefined, true).
6784514f5e3Sopenharmony_ci    property = globalConst->GetHandledUserGroupingString();
6794514f5e3Sopenharmony_ci    bool useGrouping = false;
6804514f5e3Sopenharmony_ci    [[maybe_unused]] bool find = JSLocale::GetOptionOfBool(thread, optionsObject, property, true, &useGrouping);
6814514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
6824514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> useGroupingValue(thread, JSTaggedValue(useGrouping));
6834514f5e3Sopenharmony_ci    numberFormat->SetUseGrouping(thread, useGroupingValue);
6844514f5e3Sopenharmony_ci
6854514f5e3Sopenharmony_ci    // 25. Set numberFormat.[[UseGrouping]] to useGrouping.
6864514f5e3Sopenharmony_ci    if (!useGrouping) {
6874514f5e3Sopenharmony_ci        icuNumberFormatter = icuNumberFormatter.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF);
6884514f5e3Sopenharmony_ci    }
6894514f5e3Sopenharmony_ci
6904514f5e3Sopenharmony_ci    // 26. Let signDisplay be ?
6914514f5e3Sopenharmony_ci    //  GetOption(options, "signDisplay", "string", « "auto", "never", "always", "exceptZero" », "auto").
6924514f5e3Sopenharmony_ci    property = globalConst->GetHandledSignDisplayString();
6934514f5e3Sopenharmony_ci    auto signDisplay = JSLocale::GetOptionOfString<SignDisplayOption>(
6944514f5e3Sopenharmony_ci        thread, optionsObject, property,
6954514f5e3Sopenharmony_ci        JSNumberFormat::SIGN_DISPLAY_OPTION, JSNumberFormat::SIGN_DISPLAY_OPTION_NAME,
6964514f5e3Sopenharmony_ci        SignDisplayOption::AUTO);
6974514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
6984514f5e3Sopenharmony_ci    numberFormat->SetSignDisplay(signDisplay);
6994514f5e3Sopenharmony_ci
7004514f5e3Sopenharmony_ci    // 27. Set numberFormat.[[SignDisplay]] to signDisplay.
7014514f5e3Sopenharmony_ci    // The default sign in ICU is UNUM_SIGN_AUTO which is mapped from
7024514f5e3Sopenharmony_ci    // SignDisplay::AUTO and CurrencySign::STANDARD so we can skip setting
7034514f5e3Sopenharmony_ci    // under that values for optimization.
7044514f5e3Sopenharmony_ci    CurrencySignOption currencySign = numberFormat->GetCurrencySign();
7054514f5e3Sopenharmony_ci
7064514f5e3Sopenharmony_ci    // Trans SignDisPlayOption to ICU UNumberSignDisplay and set to icuNumberFormatter
7074514f5e3Sopenharmony_ci    switch (signDisplay) {
7084514f5e3Sopenharmony_ci        case SignDisplayOption::AUTO:
7094514f5e3Sopenharmony_ci            // if CurrencySign is ACCOUNTING, Use the locale-dependent accounting format on negative numbers
7104514f5e3Sopenharmony_ci            if (currencySign == CurrencySignOption::ACCOUNTING) {
7114514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING);
7124514f5e3Sopenharmony_ci            } else {
7134514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_AUTO);
7144514f5e3Sopenharmony_ci            }
7154514f5e3Sopenharmony_ci            break;
7164514f5e3Sopenharmony_ci        case SignDisplayOption::NEVER:
7174514f5e3Sopenharmony_ci            icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_NEVER);
7184514f5e3Sopenharmony_ci            break;
7194514f5e3Sopenharmony_ci        case SignDisplayOption::ALWAYS:
7204514f5e3Sopenharmony_ci            // if CurrencySign is ACCOUNTING, Use the locale-dependent accounting format on negative numbers
7214514f5e3Sopenharmony_ci            if (currencySign == CurrencySignOption::ACCOUNTING) {
7224514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS);
7234514f5e3Sopenharmony_ci            } else {
7244514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS);
7254514f5e3Sopenharmony_ci            }
7264514f5e3Sopenharmony_ci            break;
7274514f5e3Sopenharmony_ci        case SignDisplayOption::EXCEPTZERO:
7284514f5e3Sopenharmony_ci            // if CurrencySign is ACCOUNTING, Use the locale-dependent accounting format on negative numbers
7294514f5e3Sopenharmony_ci            if (currencySign == CurrencySignOption::ACCOUNTING) {
7304514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO);
7314514f5e3Sopenharmony_ci            } else {
7324514f5e3Sopenharmony_ci                icuNumberFormatter = icuNumberFormatter.sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO);
7334514f5e3Sopenharmony_ci            }
7344514f5e3Sopenharmony_ci            break;
7354514f5e3Sopenharmony_ci        default:
7364514f5e3Sopenharmony_ci            break;
7374514f5e3Sopenharmony_ci    }
7384514f5e3Sopenharmony_ci
7394514f5e3Sopenharmony_ci    if (forIcuCache) {
7404514f5e3Sopenharmony_ci        std::string cacheEntry =
7414514f5e3Sopenharmony_ci            locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString();
7424514f5e3Sopenharmony_ci        auto formatterPointer = new icu::number::LocalizedNumberFormatter(icuNumberFormatter);
7434514f5e3Sopenharmony_ci        thread->GetCurrentEcmaContext()->SetIcuFormatterToCache(IcuFormatterType::NUMBER_FORMATTER, cacheEntry,
7444514f5e3Sopenharmony_ci            formatterPointer, JSNumberFormat::FreeIcuNumberformat);
7454514f5e3Sopenharmony_ci    } else {
7464514f5e3Sopenharmony_ci        // Set numberFormat.[[IcuNumberForma]] to handleNumberFormatter
7474514f5e3Sopenharmony_ci        factory->NewJSIntlIcuData(numberFormat, icuNumberFormatter, JSNumberFormat::FreeIcuNumberformat);
7484514f5e3Sopenharmony_ci    }
7494514f5e3Sopenharmony_ci    // Set numberFormat.[[BoundFormat]] to undefinedValue
7504514f5e3Sopenharmony_ci    numberFormat->SetBoundFormat(thread, undefinedValue);
7514514f5e3Sopenharmony_ci}
7524514f5e3Sopenharmony_ci
7534514f5e3Sopenharmony_ci// 12.1.3 CurrencyDigits ( currency )
7544514f5e3Sopenharmony_ciint32_t JSNumberFormat::CurrencyDigits(const icu::UnicodeString &currency)
7554514f5e3Sopenharmony_ci{
7564514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
7574514f5e3Sopenharmony_ci    // If the ISO 4217 currency and funds code list contains currency as an alphabetic code,
7584514f5e3Sopenharmony_ci    // return the minor unit value corresponding to the currency from the list; otherwise, return 2.
7594514f5e3Sopenharmony_ci    int32_t fractionDigits =
7604514f5e3Sopenharmony_ci        ucurr_getDefaultFractionDigits(reinterpret_cast<const UChar *>(currency.getBuffer()), &status);
7614514f5e3Sopenharmony_ci    if (U_SUCCESS(status)) {
7624514f5e3Sopenharmony_ci        return fractionDigits;
7634514f5e3Sopenharmony_ci    }
7644514f5e3Sopenharmony_ci    return JSNumberFormat::DEFAULT_FRACTION_DIGITS;
7654514f5e3Sopenharmony_ci}
7664514f5e3Sopenharmony_ci
7674514f5e3Sopenharmony_ciicu::number::LocalizedNumberFormatter *JSNumberFormat::GetCachedIcuNumberFormatter(JSThread *thread,
7684514f5e3Sopenharmony_ci    const JSHandle<JSTaggedValue> &locales)
7694514f5e3Sopenharmony_ci{
7704514f5e3Sopenharmony_ci    std::string cacheEntry = locales->IsUndefined() ? "" : EcmaStringAccessor(locales.GetTaggedValue()).ToStdString();
7714514f5e3Sopenharmony_ci    void *cachedNumberFormatter = thread->GetCurrentEcmaContext()->GetIcuFormatterFromCache(
7724514f5e3Sopenharmony_ci        IcuFormatterType::NUMBER_FORMATTER, cacheEntry);
7734514f5e3Sopenharmony_ci    if (cachedNumberFormatter) {
7744514f5e3Sopenharmony_ci        return reinterpret_cast<icu::number::LocalizedNumberFormatter*>(cachedNumberFormatter);
7754514f5e3Sopenharmony_ci    }
7764514f5e3Sopenharmony_ci    return nullptr;
7774514f5e3Sopenharmony_ci}
7784514f5e3Sopenharmony_ci
7794514f5e3Sopenharmony_ci// 12.1.8 FormatNumeric( numberFormat, x )
7804514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSNumberFormat::FormatNumeric(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat,
7814514f5e3Sopenharmony_ci                                                      JSTaggedValue x)
7824514f5e3Sopenharmony_ci{
7834514f5e3Sopenharmony_ci    icu::number::LocalizedNumberFormatter *icuNumberFormat = numberFormat->GetIcuCallTarget();
7844514f5e3Sopenharmony_ci    ASSERT(icuNumberFormat != nullptr);
7854514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> res = FormatNumeric(thread, icuNumberFormat, x);
7864514f5e3Sopenharmony_ci    return res;
7874514f5e3Sopenharmony_ci}
7884514f5e3Sopenharmony_ci
7894514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSNumberFormat::FormatNumeric(JSThread *thread,
7904514f5e3Sopenharmony_ci                                                      const icu::number::LocalizedNumberFormatter *icuNumberFormat,
7914514f5e3Sopenharmony_ci                                                      JSTaggedValue x)
7924514f5e3Sopenharmony_ci{
7934514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
7944514f5e3Sopenharmony_ci    icu::number::FormattedNumber formattedNumber;
7954514f5e3Sopenharmony_ci    if (x.IsBigInt()) {
7964514f5e3Sopenharmony_ci        JSHandle<BigInt> bigint(thread, x);
7974514f5e3Sopenharmony_ci        JSHandle<EcmaString> bigintStr = BigInt::ToString(thread, bigint);
7984514f5e3Sopenharmony_ci        std::string stdString = EcmaStringAccessor(bigintStr).ToStdString();
7994514f5e3Sopenharmony_ci        formattedNumber = icuNumberFormat->formatDecimal(icu::StringPiece(stdString), status);
8004514f5e3Sopenharmony_ci    } else {
8014514f5e3Sopenharmony_ci        double number = x.GetNumber();
8024514f5e3Sopenharmony_ci        formattedNumber = icuNumberFormat->formatDouble(number, status);
8034514f5e3Sopenharmony_ci    }
8044514f5e3Sopenharmony_ci    if (U_FAILURE(status)) {
8054514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> errorResult(thread, JSTaggedValue::Exception());
8064514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatter format failed", errorResult);
8074514f5e3Sopenharmony_ci    }
8084514f5e3Sopenharmony_ci    icu::UnicodeString result = formattedNumber.toString(status);
8094514f5e3Sopenharmony_ci    if (U_FAILURE(status)) {
8104514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> errorResult(thread, JSTaggedValue::Exception());
8114514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "formatted number toString failed", errorResult);
8124514f5e3Sopenharmony_ci    }
8134514f5e3Sopenharmony_ci    JSHandle<EcmaString> stringValue = intl::LocaleHelper::UStringToString(thread, result);
8144514f5e3Sopenharmony_ci    return JSHandle<JSTaggedValue>::Cast(stringValue);
8154514f5e3Sopenharmony_ci}
8164514f5e3Sopenharmony_ci
8174514f5e3Sopenharmony_civoid GroupToParts(JSThread *thread, const icu::number::FormattedNumber &formatted, const JSHandle<JSArray> &receiver,
8184514f5e3Sopenharmony_ci                  const JSHandle<JSNumberFormat> &numberFormat, JSTaggedValue x)
8194514f5e3Sopenharmony_ci{
8204514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
8214514f5e3Sopenharmony_ci    icu::UnicodeString formattedText = formatted.toString(status);
8224514f5e3Sopenharmony_ci    if (U_FAILURE(status)) {  // NOLINT(readability-implicit-bool-conversion)
8234514f5e3Sopenharmony_ci        THROW_TYPE_ERROR(thread, "formattedNumber toString failed");
8244514f5e3Sopenharmony_ci    }
8254514f5e3Sopenharmony_ci    ASSERT(x.IsNumber() || x.IsBigInt());
8264514f5e3Sopenharmony_ci
8274514f5e3Sopenharmony_ci    StyleOption styleOption = numberFormat->GetStyle();
8284514f5e3Sopenharmony_ci
8294514f5e3Sopenharmony_ci    icu::ConstrainedFieldPosition cfpo;
8304514f5e3Sopenharmony_ci    // Set constrainCategory to UFIELD_CATEGORY_NUMBER which is specified for UNumberFormatFields
8314514f5e3Sopenharmony_ci    cfpo.constrainCategory(UFIELD_CATEGORY_NUMBER);
8324514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
8334514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> typeString(thread, JSTaggedValue::Undefined());
8344514f5e3Sopenharmony_ci    int index = 0;
8354514f5e3Sopenharmony_ci    int previousLimit = 0;
8364514f5e3Sopenharmony_ci    /**
8374514f5e3Sopenharmony_ci     * From ICU header file document @unumberformatter.h
8384514f5e3Sopenharmony_ci     * Sets a constraint on the field category.
8394514f5e3Sopenharmony_ci     *
8404514f5e3Sopenharmony_ci     * When this instance of ConstrainedFieldPosition is passed to FormattedValue#nextPosition,
8414514f5e3Sopenharmony_ci     * positions are skipped unless they have the given category.
8424514f5e3Sopenharmony_ci     *
8434514f5e3Sopenharmony_ci     * Any previously set constraints are cleared.
8444514f5e3Sopenharmony_ci     *
8454514f5e3Sopenharmony_ci     * For example, to loop over only the number-related fields:
8464514f5e3Sopenharmony_ci     *
8474514f5e3Sopenharmony_ci     *     ConstrainedFieldPosition cfpo;
8484514f5e3Sopenharmony_ci     *     cfpo.constrainCategory(UFIELDCATEGORY_NUMBER_FORMAT);
8494514f5e3Sopenharmony_ci     *     while (fmtval.nextPosition(cfpo, status)) {
8504514f5e3Sopenharmony_ci     *         // handle the number-related field position
8514514f5e3Sopenharmony_ci     *     }
8524514f5e3Sopenharmony_ci     */
8534514f5e3Sopenharmony_ci    bool lastFieldGroup = false;
8544514f5e3Sopenharmony_ci    int groupLeapLength = 0;
8554514f5e3Sopenharmony_ci    while (formatted.nextPosition(cfpo, status)) {
8564514f5e3Sopenharmony_ci        int32_t fieldId = cfpo.getField();
8574514f5e3Sopenharmony_ci        int32_t start = cfpo.getStart();
8584514f5e3Sopenharmony_ci        int32_t limit = cfpo.getLimit();
8594514f5e3Sopenharmony_ci        typeString.Update(globalConst->GetLiteralString());
8604514f5e3Sopenharmony_ci        // If start greater than previousLimit, means a literal type exists before number fields
8614514f5e3Sopenharmony_ci        // so add a literal type with value of formattedText.sub(0, start)
8624514f5e3Sopenharmony_ci        // Special case when fieldId is UNUM_GROUPING_SEPARATOR_FIELD
8634514f5e3Sopenharmony_ci        if (static_cast<UNumberFormatFields>(fieldId) == UNUM_GROUPING_SEPARATOR_FIELD) {
8644514f5e3Sopenharmony_ci            JSHandle<EcmaString> substring =
8654514f5e3Sopenharmony_ci                intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start);
8664514f5e3Sopenharmony_ci            typeString.Update(globalConst->GetIntegerString());
8674514f5e3Sopenharmony_ci            JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
8684514f5e3Sopenharmony_ci            RETURN_IF_ABRUPT_COMPLETION(thread);
8694514f5e3Sopenharmony_ci            index++;
8704514f5e3Sopenharmony_ci            {
8714514f5e3Sopenharmony_ci                typeString.Update(JSLocale::GetNumberFieldType(thread, x, fieldId).GetTaggedValue());
8724514f5e3Sopenharmony_ci                substring = intl::LocaleHelper::UStringToString(thread, formattedText, start, limit);
8734514f5e3Sopenharmony_ci                JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
8744514f5e3Sopenharmony_ci                RETURN_IF_ABRUPT_COMPLETION(thread);
8754514f5e3Sopenharmony_ci                index++;
8764514f5e3Sopenharmony_ci            }
8774514f5e3Sopenharmony_ci            lastFieldGroup = true;
8784514f5e3Sopenharmony_ci            groupLeapLength = start - previousLimit + 1;
8794514f5e3Sopenharmony_ci            previousLimit = limit;
8804514f5e3Sopenharmony_ci            continue;
8814514f5e3Sopenharmony_ci        } else if (start > previousLimit) {
8824514f5e3Sopenharmony_ci            JSHandle<EcmaString> substring =
8834514f5e3Sopenharmony_ci                intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, start);
8844514f5e3Sopenharmony_ci            JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
8854514f5e3Sopenharmony_ci            RETURN_IF_ABRUPT_COMPLETION(thread);
8864514f5e3Sopenharmony_ci            index++;
8874514f5e3Sopenharmony_ci        }
8884514f5e3Sopenharmony_ci        if (lastFieldGroup) {
8894514f5e3Sopenharmony_ci            start = start + groupLeapLength;
8904514f5e3Sopenharmony_ci            lastFieldGroup = false;
8914514f5e3Sopenharmony_ci        }
8924514f5e3Sopenharmony_ci        // Special case in ICU when style is unit and unit is percent
8934514f5e3Sopenharmony_ci        if (styleOption == StyleOption::UNIT && static_cast<UNumberFormatFields>(fieldId) == UNUM_PERCENT_FIELD) {
8944514f5e3Sopenharmony_ci            typeString.Update(globalConst->GetUnitString());
8954514f5e3Sopenharmony_ci        } else {
8964514f5e3Sopenharmony_ci            typeString.Update(JSLocale::GetNumberFieldType(thread, x, fieldId).GetTaggedValue());
8974514f5e3Sopenharmony_ci        }
8984514f5e3Sopenharmony_ci        JSHandle<EcmaString> substring = intl::LocaleHelper::UStringToString(thread, formattedText, start, limit);
8994514f5e3Sopenharmony_ci        JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
9004514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
9014514f5e3Sopenharmony_ci        index++;
9024514f5e3Sopenharmony_ci        previousLimit = limit;
9034514f5e3Sopenharmony_ci    }
9044514f5e3Sopenharmony_ci    // If iterated length is smaller than formattedText.length, means a literal type exists after number fields
9054514f5e3Sopenharmony_ci    // so add a literal type with value of formattedText.sub(previousLimit, formattedText.length)
9064514f5e3Sopenharmony_ci    if (formattedText.length() > previousLimit) {
9074514f5e3Sopenharmony_ci        typeString.Update(globalConst->GetLiteralString());
9084514f5e3Sopenharmony_ci        JSHandle<EcmaString> substring =
9094514f5e3Sopenharmony_ci            intl::LocaleHelper::UStringToString(thread, formattedText, previousLimit, formattedText.length());
9104514f5e3Sopenharmony_ci        JSLocale::PutElement(thread, index, receiver, typeString, JSHandle<JSTaggedValue>::Cast(substring));
9114514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
9124514f5e3Sopenharmony_ci    }
9134514f5e3Sopenharmony_ci}
9144514f5e3Sopenharmony_ci
9154514f5e3Sopenharmony_ci// 12.1.9 FormatNumericToParts( numberFormat, x )
9164514f5e3Sopenharmony_ciJSHandle<JSArray> JSNumberFormat::FormatNumericToParts(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat,
9174514f5e3Sopenharmony_ci                                                       JSTaggedValue x)
9184514f5e3Sopenharmony_ci{
9194514f5e3Sopenharmony_ci    ASSERT(x.IsNumber() || x.IsBigInt());
9204514f5e3Sopenharmony_ci    icu::number::LocalizedNumberFormatter *icuNumberFormatter = numberFormat->GetIcuCallTarget();
9214514f5e3Sopenharmony_ci    ASSERT(icuNumberFormatter != nullptr);
9224514f5e3Sopenharmony_ci
9234514f5e3Sopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
9244514f5e3Sopenharmony_ci    icu::number::FormattedNumber formattedNumber;
9254514f5e3Sopenharmony_ci    if (x.IsBigInt()) {
9264514f5e3Sopenharmony_ci        JSHandle<BigInt> bigint(thread, x);
9274514f5e3Sopenharmony_ci        JSHandle<EcmaString> bigintStr = BigInt::ToString(thread, bigint);
9284514f5e3Sopenharmony_ci        std::string stdString = EcmaStringAccessor(bigintStr).ToStdString();
9294514f5e3Sopenharmony_ci        formattedNumber = icuNumberFormatter->formatDecimal(icu::StringPiece(stdString), status);
9304514f5e3Sopenharmony_ci    } else {
9314514f5e3Sopenharmony_ci        double number = x.GetNumber();
9324514f5e3Sopenharmony_ci        formattedNumber = icuNumberFormatter->formatDouble(number, status);
9334514f5e3Sopenharmony_ci    }
9344514f5e3Sopenharmony_ci    if (U_FAILURE(status)) {
9354514f5e3Sopenharmony_ci        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
9364514f5e3Sopenharmony_ci        JSHandle<JSArray> emptyArray = factory->NewJSArray();
9374514f5e3Sopenharmony_ci        THROW_RANGE_ERROR_AND_RETURN(thread, "icu formatter format failed", emptyArray);
9384514f5e3Sopenharmony_ci    }
9394514f5e3Sopenharmony_ci
9404514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> arr = JSArray::ArrayCreate(thread, JSTaggedNumber(0));
9414514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
9424514f5e3Sopenharmony_ci    JSHandle<JSArray> result = JSHandle<JSArray>::Cast(arr);
9434514f5e3Sopenharmony_ci    GroupToParts(thread, formattedNumber, result, numberFormat, x);
9444514f5e3Sopenharmony_ci    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSArray, thread);
9454514f5e3Sopenharmony_ci    return result;
9464514f5e3Sopenharmony_ci}
9474514f5e3Sopenharmony_ci
9484514f5e3Sopenharmony_ci// 12.1.12 UnwrapNumberFormat( nf )
9494514f5e3Sopenharmony_ciJSHandle<JSTaggedValue> JSNumberFormat::UnwrapNumberFormat(JSThread *thread, const JSHandle<JSTaggedValue> &nf)
9504514f5e3Sopenharmony_ci{
9514514f5e3Sopenharmony_ci    // 1. Assert: Type(nf) is Object.
9524514f5e3Sopenharmony_ci    ASSERT(nf->IsJSObject());
9534514f5e3Sopenharmony_ci
9544514f5e3Sopenharmony_ci    // 2. If nf does not have an [[InitializedNumberFormat]] internal slot and ?
9554514f5e3Sopenharmony_ci    //  InstanceofOperator(nf, %NumberFormat%) is true, then Let nf be ? Get(nf, %Intl%.[[FallbackSymbol]]).
9564514f5e3Sopenharmony_ci    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
9574514f5e3Sopenharmony_ci    bool hasInstance = JSFunction::OrdinaryHasInstance(thread, env->GetNumberFormatFunction(), nf);
9584514f5e3Sopenharmony_ci    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
9594514f5e3Sopenharmony_ci
9604514f5e3Sopenharmony_ci    bool isJSNumberFormat = nf->IsJSNumberFormat();
9614514f5e3Sopenharmony_ci    // If nf does not have an [[InitializedNumberFormat]] internal slot and ?
9624514f5e3Sopenharmony_ci    // InstanceofOperator(nf, %NumberFormat%) is true, then
9634514f5e3Sopenharmony_ci    //      a. Let nf be ? Get(nf, %Intl%.[[FallbackSymbol]]).
9644514f5e3Sopenharmony_ci    if (!isJSNumberFormat && hasInstance) {
9654514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> key(thread, JSHandle<JSIntl>::Cast(env->GetIntlFunction())->GetFallbackSymbol());
9664514f5e3Sopenharmony_ci        OperationResult operationResult = JSTaggedValue::GetProperty(thread, nf, key);
9674514f5e3Sopenharmony_ci        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
9684514f5e3Sopenharmony_ci        return operationResult.GetValue();
9694514f5e3Sopenharmony_ci    }
9704514f5e3Sopenharmony_ci    // 3. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
9714514f5e3Sopenharmony_ci    if (!isJSNumberFormat) {
9724514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "this is not object",
9734514f5e3Sopenharmony_ci                                    JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
9744514f5e3Sopenharmony_ci    }
9754514f5e3Sopenharmony_ci    return nf;
9764514f5e3Sopenharmony_ci}
9774514f5e3Sopenharmony_ci
9784514f5e3Sopenharmony_ciJSHandle<TaggedArray> JSNumberFormat::GetAvailableLocales(JSThread *thread)
9794514f5e3Sopenharmony_ci{
9804514f5e3Sopenharmony_ci    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
9814514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> numberFormatLocales = env->GetNumberFormatLocales();
9824514f5e3Sopenharmony_ci    if (!numberFormatLocales->IsUndefined()) {
9834514f5e3Sopenharmony_ci        return JSHandle<TaggedArray>::Cast(numberFormatLocales);
9844514f5e3Sopenharmony_ci    }
9854514f5e3Sopenharmony_ci    const char *key = "NumberElements";
9864514f5e3Sopenharmony_ci    const char *path = nullptr;
9874514f5e3Sopenharmony_ci    std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path);
9884514f5e3Sopenharmony_ci    JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
9894514f5e3Sopenharmony_ci    env->SetNumberFormatLocales(thread, availableLocales);
9904514f5e3Sopenharmony_ci    return availableLocales;
9914514f5e3Sopenharmony_ci}
9924514f5e3Sopenharmony_ci
9934514f5e3Sopenharmony_civoid JSNumberFormat::ResolvedOptions(JSThread *thread, const JSHandle<JSNumberFormat> &numberFormat,
9944514f5e3Sopenharmony_ci                                     const JSHandle<JSObject> &options)
9954514f5e3Sopenharmony_ci{
9964514f5e3Sopenharmony_ci    // Table 5: Resolved Options of NumberFormat Instances
9974514f5e3Sopenharmony_ci    // Internal Slot                    Property
9984514f5e3Sopenharmony_ci    //    [[Locale]]                      "locale"
9994514f5e3Sopenharmony_ci    //    [[NumberingSystem]]             "numberingSystem"
10004514f5e3Sopenharmony_ci    //    [[Style]]                       "style"
10014514f5e3Sopenharmony_ci    //    [[Currency]]                    "currency"
10024514f5e3Sopenharmony_ci    //    [[CurrencyDisplay]]             "currencyDisplay"
10034514f5e3Sopenharmony_ci    //    [[CurrencySign]]                "currencySign"
10044514f5e3Sopenharmony_ci    //    [[Unit]]                        "unit"
10054514f5e3Sopenharmony_ci    //    [[UnitDisplay]]                 "unitDisplay"
10064514f5e3Sopenharmony_ci    //    [[MinimumIntegerDigits]]        "minimumIntegerDigits"
10074514f5e3Sopenharmony_ci    //    [[MinimumFractionDigits]]       "minimumFractionDigits"
10084514f5e3Sopenharmony_ci    //    [[MaximumFractionDigits]]       "maximumFractionDigits"
10094514f5e3Sopenharmony_ci    //    [[MinimumSignificantDigits]]    "minimumSignificantDigits"
10104514f5e3Sopenharmony_ci    //    [[MaximumSignificantDigits]]    "maximumSignificantDigits"
10114514f5e3Sopenharmony_ci    //    [[UseGrouping]]                 "useGrouping"
10124514f5e3Sopenharmony_ci    //    [[Notation]]                    "notation"
10134514f5e3Sopenharmony_ci    //    [[CompactDisplay]]              "compactDisplay"
10144514f5e3Sopenharmony_ci    //    [SignDisplay]]                  "signDisplay"
10154514f5e3Sopenharmony_ci    // [[Locale]]
10164514f5e3Sopenharmony_ci    auto globalConst = thread->GlobalConstants();
10174514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> property = globalConst->GetHandledLocaleString();
10184514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> locale(thread, numberFormat->GetLocale());
10194514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property, locale);
10204514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
10214514f5e3Sopenharmony_ci
10224514f5e3Sopenharmony_ci    // [[NumberingSystem]]
10234514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> numberingSystem(thread, numberFormat->GetNumberingSystem());
10244514f5e3Sopenharmony_ci    if (numberingSystem->IsUndefined()) {
10254514f5e3Sopenharmony_ci        numberingSystem = globalConst->GetHandledLatnString();
10264514f5e3Sopenharmony_ci    }
10274514f5e3Sopenharmony_ci    property = globalConst->GetHandledNumberingSystemString();
10284514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property, numberingSystem);
10294514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
10304514f5e3Sopenharmony_ci
10314514f5e3Sopenharmony_ci    // [[Style]]
10324514f5e3Sopenharmony_ci    StyleOption style = numberFormat->GetStyle();
10334514f5e3Sopenharmony_ci    property = globalConst->GetHandledStyleString();
10344514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> styleString = OptionToEcmaString(thread, style);
10354514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property, styleString);
10364514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
10374514f5e3Sopenharmony_ci
10384514f5e3Sopenharmony_ci    // [[currency]]
10394514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> currency(thread, JSTaggedValue::Undefined());
10404514f5e3Sopenharmony_ci    // If style is not currency the currency should be undefined
10414514f5e3Sopenharmony_ci    if (style == StyleOption::CURRENCY) {
10424514f5e3Sopenharmony_ci        currency = JSHandle<JSTaggedValue>(thread, numberFormat->GetCurrency());
10434514f5e3Sopenharmony_ci    }
10444514f5e3Sopenharmony_ci    if (!currency->IsUndefined()) {  // NOLINT(readability-implicit-bool-conversion)
10454514f5e3Sopenharmony_ci        property = globalConst->GetHandledCurrencyString();
10464514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, currency);
10474514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
10484514f5e3Sopenharmony_ci
10494514f5e3Sopenharmony_ci        // [[CurrencyDisplay]]
10504514f5e3Sopenharmony_ci        property = globalConst->GetHandledCurrencyDisplayString();
10514514f5e3Sopenharmony_ci        CurrencyDisplayOption currencyDisplay = numberFormat->GetCurrencyDisplay();
10524514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> currencyDisplayString = OptionToEcmaString(thread, currencyDisplay);
10534514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, currencyDisplayString);
10544514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
10554514f5e3Sopenharmony_ci
10564514f5e3Sopenharmony_ci        // [[CurrencySign]]
10574514f5e3Sopenharmony_ci        property = globalConst->GetHandledCurrencySignString();
10584514f5e3Sopenharmony_ci        CurrencySignOption currencySign = numberFormat->GetCurrencySign();
10594514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> currencySignString = OptionToEcmaString(thread, currencySign);
10604514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, currencySignString);
10614514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
10624514f5e3Sopenharmony_ci    }
10634514f5e3Sopenharmony_ci
10644514f5e3Sopenharmony_ci    if (style == StyleOption::UNIT) {
10654514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> unit(thread, numberFormat->GetUnit());
10664514f5e3Sopenharmony_ci        if (!unit->IsUndefined()) {
10674514f5e3Sopenharmony_ci            // [[Unit]]
10684514f5e3Sopenharmony_ci            property = globalConst->GetHandledUnitString();
10694514f5e3Sopenharmony_ci            JSObject::CreateDataPropertyOrThrow(thread, options, property, unit);
10704514f5e3Sopenharmony_ci            RETURN_IF_ABRUPT_COMPLETION(thread);
10714514f5e3Sopenharmony_ci        }
10724514f5e3Sopenharmony_ci        // [[UnitDisplay]]
10734514f5e3Sopenharmony_ci        property = globalConst->GetHandledUnitDisplayString();
10744514f5e3Sopenharmony_ci        UnitDisplayOption unitDisplay = numberFormat->GetUnitDisplay();
10754514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> unitDisplayString = OptionToEcmaString(thread, unitDisplay);
10764514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, unitDisplayString);
10774514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
10784514f5e3Sopenharmony_ci    }
10794514f5e3Sopenharmony_ci    // [[MinimumIntegerDigits]]
10804514f5e3Sopenharmony_ci    property = globalConst->GetHandledMinimumIntegerDigitsString();
10814514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> minimumIntegerDigits(thread, numberFormat->GetMinimumIntegerDigits());
10824514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumIntegerDigits);
10834514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
10844514f5e3Sopenharmony_ci
10854514f5e3Sopenharmony_ci    RoundingType roundingType = numberFormat->GetRoundingType();
10864514f5e3Sopenharmony_ci    if (roundingType == RoundingType::SIGNIFICANTDIGITS) {
10874514f5e3Sopenharmony_ci        // [[MinimumSignificantDigits]]
10884514f5e3Sopenharmony_ci        property = globalConst->GetHandledMinimumSignificantDigitsString();
10894514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> minimumSignificantDigits(thread, numberFormat->GetMinimumSignificantDigits());
10904514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumSignificantDigits);
10914514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
10924514f5e3Sopenharmony_ci        // [[MaximumSignificantDigits]]
10934514f5e3Sopenharmony_ci        property = globalConst->GetHandledMaximumSignificantDigitsString();
10944514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> maximumSignificantDigits(thread, numberFormat->GetMaximumSignificantDigits());
10954514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumSignificantDigits);
10964514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
10974514f5e3Sopenharmony_ci    } else {
10984514f5e3Sopenharmony_ci        // [[MinimumFractionDigits]]
10994514f5e3Sopenharmony_ci        property = globalConst->GetHandledMinimumFractionDigitsString();
11004514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> minimumFractionDigits(thread, numberFormat->GetMinimumFractionDigits());
11014514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumFractionDigits);
11024514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
11034514f5e3Sopenharmony_ci        // [[MaximumFractionDigits]]
11044514f5e3Sopenharmony_ci        property = globalConst->GetHandledMaximumFractionDigitsString();
11054514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> maximumFractionDigits(thread, numberFormat->GetMaximumFractionDigits());
11064514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumFractionDigits);
11074514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
11084514f5e3Sopenharmony_ci
11094514f5e3Sopenharmony_ci        // in v3, should contain BOTH significant and fraction digits
11104514f5e3Sopenharmony_ci        if (roundingType == RoundingType::COMPACTROUNDING) {
11114514f5e3Sopenharmony_ci            // [[MinimumSignificantDigits]]
11124514f5e3Sopenharmony_ci            property = globalConst->GetHandledMinimumSignificantDigitsString();
11134514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> minimumSignificantDigits(thread, numberFormat->GetMinimumSignificantDigits());
11144514f5e3Sopenharmony_ci            JSObject::CreateDataPropertyOrThrow(thread, options, property, minimumSignificantDigits);
11154514f5e3Sopenharmony_ci            RETURN_IF_ABRUPT_COMPLETION(thread);
11164514f5e3Sopenharmony_ci            // [[MaximumSignificantDigits]]
11174514f5e3Sopenharmony_ci            property = globalConst->GetHandledMaximumSignificantDigitsString();
11184514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> maximumSignificantDigits(thread, numberFormat->GetMaximumSignificantDigits());
11194514f5e3Sopenharmony_ci            JSObject::CreateDataPropertyOrThrow(thread, options, property, maximumSignificantDigits);
11204514f5e3Sopenharmony_ci            RETURN_IF_ABRUPT_COMPLETION(thread);
11214514f5e3Sopenharmony_ci        }
11224514f5e3Sopenharmony_ci    }
11234514f5e3Sopenharmony_ci
11244514f5e3Sopenharmony_ci    // [[UseGrouping]]
11254514f5e3Sopenharmony_ci    property = globalConst->GetHandledUserGroupingString();
11264514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property,
11274514f5e3Sopenharmony_ci                                        JSHandle<JSTaggedValue>(thread, numberFormat->GetUseGrouping()));
11284514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
11294514f5e3Sopenharmony_ci
11304514f5e3Sopenharmony_ci    // [[Notation]]
11314514f5e3Sopenharmony_ci    property = globalConst->GetHandledNotationString();
11324514f5e3Sopenharmony_ci    NotationOption notation = numberFormat->GetNotation();
11334514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> notationString = OptionToEcmaString(thread, notation);
11344514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property, notationString);
11354514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
11364514f5e3Sopenharmony_ci
11374514f5e3Sopenharmony_ci    // Only output compactDisplay when notation is compact.
11384514f5e3Sopenharmony_ci    if (notation == NotationOption::COMPACT) {
11394514f5e3Sopenharmony_ci        // [[CompactDisplay]]
11404514f5e3Sopenharmony_ci        property = globalConst->GetHandledCompactDisplayString();
11414514f5e3Sopenharmony_ci        CompactDisplayOption compactDisplay = numberFormat->GetCompactDisplay();
11424514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> compactDisplayString = OptionToEcmaString(thread, compactDisplay);
11434514f5e3Sopenharmony_ci        JSObject::CreateDataPropertyOrThrow(thread, options, property, compactDisplayString);
11444514f5e3Sopenharmony_ci        RETURN_IF_ABRUPT_COMPLETION(thread);
11454514f5e3Sopenharmony_ci    }
11464514f5e3Sopenharmony_ci
11474514f5e3Sopenharmony_ci    // [[SignDisplay]]
11484514f5e3Sopenharmony_ci    property = globalConst->GetHandledSignDisplayString();
11494514f5e3Sopenharmony_ci    SignDisplayOption signDisplay = numberFormat->GetSignDisplay();
11504514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> signDisplayString = OptionToEcmaString(thread, signDisplay);
11514514f5e3Sopenharmony_ci    JSObject::CreateDataPropertyOrThrow(thread, options, property, signDisplayString);
11524514f5e3Sopenharmony_ci    RETURN_IF_ABRUPT_COMPLETION(thread);
11534514f5e3Sopenharmony_ci}
11544514f5e3Sopenharmony_ci}  // namespace panda::ecmascript