tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ListFormat.js (7636B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /**
      6 * ListFormat internal properties.
      7 */
      8 function listFormatLocaleData() {
      9  // ListFormat don't support any extension keys.
     10  return {};
     11 }
     12 var listFormatInternalProperties = {
     13  localeData: listFormatLocaleData,
     14  relevantExtensionKeys: [],
     15 };
     16 
     17 /**
     18 * Intl.ListFormat ( [ locales [ , options ] ] )
     19 *
     20 * Compute an internal properties object from |lazyListFormatData|.
     21 */
     22 function resolveListFormatInternals(lazyListFormatData) {
     23  assert(IsObject(lazyListFormatData), "lazy data not an object?");
     24 
     25  var internalProps = std_Object_create(null);
     26 
     27  var ListFormat = listFormatInternalProperties;
     28 
     29  // Compute effective locale.
     30 
     31  // Step 9.
     32  var localeData = ListFormat.localeData;
     33 
     34  // Step 10.
     35  var r = ResolveLocale(
     36    "ListFormat",
     37    lazyListFormatData.requestedLocales,
     38    lazyListFormatData.opt,
     39    ListFormat.relevantExtensionKeys,
     40    localeData
     41  );
     42 
     43  // Step 11.
     44  internalProps.locale = r.locale;
     45 
     46  // Step 13.
     47  internalProps.type = lazyListFormatData.type;
     48 
     49  // Step 15.
     50  internalProps.style = lazyListFormatData.style;
     51 
     52  // Steps 16-23 (not applicable in our implementation).
     53 
     54  // The caller is responsible for associating |internalProps| with the right
     55  // object using |setInternalProperties|.
     56  return internalProps;
     57 }
     58 
     59 /**
     60 * Returns an object containing the ListFormat internal properties of |obj|.
     61 */
     62 function getListFormatInternals(obj) {
     63  assert(IsObject(obj), "getListFormatInternals called with non-object");
     64  assert(
     65    intl_GuardToListFormat(obj) !== null,
     66    "getListFormatInternals called with non-ListFormat"
     67  );
     68 
     69  var internals = getIntlObjectInternals(obj);
     70  assert(
     71    internals.type === "ListFormat",
     72    "bad type escaped getIntlObjectInternals"
     73  );
     74 
     75  // If internal properties have already been computed, use them.
     76  var internalProps = maybeInternalProperties(internals);
     77  if (internalProps) {
     78    return internalProps;
     79  }
     80 
     81  // Otherwise it's time to fully create them.
     82  internalProps = resolveListFormatInternals(internals.lazyData);
     83  setInternalProperties(internals, internalProps);
     84  return internalProps;
     85 }
     86 
     87 /**
     88 * Intl.ListFormat ( [ locales [ , options ] ] )
     89 *
     90 * Initializes an object as a ListFormat.
     91 *
     92 * This method is complicated a moderate bit by its implementing initialization
     93 * as a *lazy* concept.  Everything that must happen now, does -- but we defer
     94 * all the work we can until the object is actually used as a ListFormat.
     95 * This later work occurs in |resolveListFormatInternals|; steps not noted
     96 * here occur there.
     97 */
     98 function InitializeListFormat(listFormat, locales, options) {
     99  assert(IsObject(listFormat), "InitializeListFormat called with non-object");
    100  assert(
    101    intl_GuardToListFormat(listFormat) !== null,
    102    "InitializeListFormat called with non-ListFormat"
    103  );
    104 
    105  // Lazy ListFormat data has the following structure:
    106  //
    107  //   {
    108  //     requestedLocales: List of locales,
    109  //     type: "conjunction" / "disjunction" / "unit",
    110  //     style: "long" / "short" / "narrow",
    111  //
    112  //     opt: // opt object computed in InitializeListFormat
    113  //       {
    114  //         localeMatcher: "lookup" / "best fit",
    115  //       }
    116  //   }
    117  //
    118  // Note that lazy data is only installed as a final step of initialization,
    119  // so every ListFormat lazy data object has *all* these properties, never a
    120  // subset of them.
    121  var lazyListFormatData = std_Object_create(null);
    122 
    123  // Step 3.
    124  var requestedLocales = CanonicalizeLocaleList(locales);
    125  lazyListFormatData.requestedLocales = requestedLocales;
    126 
    127  // Steps 4-5.
    128  if (options === undefined) {
    129    options = std_Object_create(null);
    130  } else if (!IsObject(options)) {
    131    ThrowTypeError(
    132      JSMSG_OBJECT_REQUIRED,
    133      options === null ? "null" : typeof options
    134    );
    135  }
    136 
    137  // Step 6.
    138  var opt = NEW_RECORD();
    139  lazyListFormatData.opt = opt;
    140 
    141  // Steps 7-8.
    142  var matcher = GetOption(
    143    options,
    144    "localeMatcher",
    145    "string",
    146    ["lookup", "best fit"],
    147    "best fit"
    148  );
    149  opt.localeMatcher = matcher;
    150 
    151  // Compute formatting options.
    152 
    153  // Steps 12-13.
    154  var type = GetOption(
    155    options,
    156    "type",
    157    "string",
    158    ["conjunction", "disjunction", "unit"],
    159    "conjunction"
    160  );
    161  lazyListFormatData.type = type;
    162 
    163  // Steps 14-15.
    164  var style = GetOption(
    165    options,
    166    "style",
    167    "string",
    168    ["long", "short", "narrow"],
    169    "long"
    170  );
    171  lazyListFormatData.style = style;
    172 
    173  // We've done everything that must be done now: mark the lazy data as fully
    174  // computed and install it.
    175  initializeIntlObject(listFormat, "ListFormat", lazyListFormatData);
    176 }
    177 
    178 /**
    179 * StringListFromIterable ( iterable )
    180 */
    181 function StringListFromIterable(iterable, methodName) {
    182  // Step 1.
    183  if (iterable === undefined) {
    184    return [];
    185  }
    186 
    187  // Step 3.
    188  var list = [];
    189 
    190  // Steps 2, 4-5.
    191  for (var element of allowContentIter(iterable)) {
    192    // Step 5.b.ii.
    193    if (typeof element !== "string") {
    194      ThrowTypeError(
    195        JSMSG_NOT_EXPECTED_TYPE,
    196        methodName,
    197        "string",
    198        typeof element
    199      );
    200    }
    201 
    202    // Step 5.b.iii.
    203    DefineDataProperty(list, list.length, element);
    204  }
    205 
    206  // Step 6.
    207  return list;
    208 }
    209 
    210 /**
    211 * Intl.ListFormat.prototype.format ( list )
    212 */
    213 function Intl_ListFormat_format(list) {
    214  // Step 1.
    215  var listFormat = this;
    216 
    217  // Steps 2-3.
    218  if (
    219    !IsObject(listFormat) ||
    220    (listFormat = intl_GuardToListFormat(listFormat)) === null
    221  ) {
    222    return callFunction(
    223      intl_CallListFormatMethodIfWrapped,
    224      this,
    225      list,
    226      "Intl_ListFormat_format"
    227    );
    228  }
    229 
    230  // Step 4.
    231  var stringList = StringListFromIterable(list, "format");
    232 
    233  // We can directly return if |stringList| contains less than two elements.
    234  if (stringList.length < 2) {
    235    return stringList.length === 0 ? "" : stringList[0];
    236  }
    237 
    238  // Ensure the ListFormat internals are resolved.
    239  getListFormatInternals(listFormat);
    240 
    241  // Step 5.
    242  return intl_FormatList(listFormat, stringList, /* formatToParts = */ false);
    243 }
    244 
    245 /**
    246 * Intl.ListFormat.prototype.formatToParts ( list )
    247 */
    248 function Intl_ListFormat_formatToParts(list) {
    249  // Step 1.
    250  var listFormat = this;
    251 
    252  // Steps 2-3.
    253  if (
    254    !IsObject(listFormat) ||
    255    (listFormat = intl_GuardToListFormat(listFormat)) === null
    256  ) {
    257    return callFunction(
    258      intl_CallListFormatMethodIfWrapped,
    259      this,
    260      list,
    261      "Intl_ListFormat_formatToParts"
    262    );
    263  }
    264 
    265  // Step 4.
    266  var stringList = StringListFromIterable(list, "formatToParts");
    267 
    268  // We can directly return if |stringList| contains less than two elements.
    269  if (stringList.length < 2) {
    270    return stringList.length === 0
    271      ? []
    272      : [{ type: "element", value: stringList[0] }];
    273  }
    274 
    275  // Ensure the ListFormat internals are resolved.
    276  getListFormatInternals(listFormat);
    277 
    278  // Step 5.
    279  return intl_FormatList(listFormat, stringList, /* formatToParts = */ true);
    280 }
    281 
    282 /**
    283 * Returns the resolved options for a ListFormat object.
    284 */
    285 function Intl_ListFormat_resolvedOptions() {
    286  // Step 1.
    287  var listFormat = this;
    288 
    289  // Steps 2-3.
    290  if (
    291    !IsObject(listFormat) ||
    292    (listFormat = intl_GuardToListFormat(listFormat)) === null
    293  ) {
    294    return callFunction(
    295      intl_CallListFormatMethodIfWrapped,
    296      this,
    297      "Intl_ListFormat_resolvedOptions"
    298    );
    299  }
    300 
    301  var internals = getListFormatInternals(listFormat);
    302 
    303  // Steps 4-5.
    304  var result = {
    305    locale: internals.locale,
    306    type: internals.type,
    307    style: internals.style,
    308  };
    309 
    310  // Step 6.
    311  return result;
    312 }