summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/intl/ListFormat.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin/intl/ListFormat.js')
-rw-r--r--js/src/builtin/intl/ListFormat.js330
1 files changed, 330 insertions, 0 deletions
diff --git a/js/src/builtin/intl/ListFormat.js b/js/src/builtin/intl/ListFormat.js
new file mode 100644
index 0000000000..463c669a44
--- /dev/null
+++ b/js/src/builtin/intl/ListFormat.js
@@ -0,0 +1,330 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * ListFormat internal properties.
+ */
+function listFormatLocaleData() {
+ // ListFormat don't support any extension keys.
+ return {};
+}
+var listFormatInternalProperties = {
+ localeData: listFormatLocaleData,
+ relevantExtensionKeys: [],
+};
+
+/**
+ * Intl.ListFormat ( [ locales [ , options ] ] )
+ *
+ * Compute an internal properties object from |lazyListFormatData|.
+ */
+function resolveListFormatInternals(lazyListFormatData) {
+ assert(IsObject(lazyListFormatData), "lazy data not an object?");
+
+ var internalProps = std_Object_create(null);
+
+ var ListFormat = listFormatInternalProperties;
+
+ // Compute effective locale.
+
+ // Step 9.
+ var localeData = ListFormat.localeData;
+
+ // Step 10.
+ var r = ResolveLocale(
+ "ListFormat",
+ lazyListFormatData.requestedLocales,
+ lazyListFormatData.opt,
+ ListFormat.relevantExtensionKeys,
+ localeData
+ );
+
+ // Step 11.
+ internalProps.locale = r.locale;
+
+ // Step 13.
+ internalProps.type = lazyListFormatData.type;
+
+ // Step 15.
+ internalProps.style = lazyListFormatData.style;
+
+ // Steps 16-23 (not applicable in our implementation).
+
+ // The caller is responsible for associating |internalProps| with the right
+ // object using |setInternalProperties|.
+ return internalProps;
+}
+
+/**
+ * Returns an object containing the ListFormat internal properties of |obj|.
+ */
+function getListFormatInternals(obj) {
+ assert(IsObject(obj), "getListFormatInternals called with non-object");
+ assert(
+ intl_GuardToListFormat(obj) !== null,
+ "getListFormatInternals called with non-ListFormat"
+ );
+
+ var internals = getIntlObjectInternals(obj);
+ assert(
+ internals.type === "ListFormat",
+ "bad type escaped getIntlObjectInternals"
+ );
+
+ // If internal properties have already been computed, use them.
+ var internalProps = maybeInternalProperties(internals);
+ if (internalProps) {
+ return internalProps;
+ }
+
+ // Otherwise it's time to fully create them.
+ internalProps = resolveListFormatInternals(internals.lazyData);
+ setInternalProperties(internals, internalProps);
+ return internalProps;
+}
+
+/**
+ * Intl.ListFormat ( [ locales [ , options ] ] )
+ *
+ * Initializes an object as a ListFormat.
+ *
+ * This method is complicated a moderate bit by its implementing initialization
+ * as a *lazy* concept. Everything that must happen now, does -- but we defer
+ * all the work we can until the object is actually used as a ListFormat.
+ * This later work occurs in |resolveListFormatInternals|; steps not noted
+ * here occur there.
+ */
+function InitializeListFormat(listFormat, locales, options) {
+ assert(IsObject(listFormat), "InitializeListFormat called with non-object");
+ assert(
+ intl_GuardToListFormat(listFormat) !== null,
+ "InitializeListFormat called with non-ListFormat"
+ );
+
+ // Lazy ListFormat data has the following structure:
+ //
+ // {
+ // requestedLocales: List of locales,
+ // type: "conjunction" / "disjunction" / "unit",
+ // style: "long" / "short" / "narrow",
+ //
+ // opt: // opt object computed in InitializeListFormat
+ // {
+ // localeMatcher: "lookup" / "best fit",
+ // }
+ // }
+ //
+ // Note that lazy data is only installed as a final step of initialization,
+ // so every ListFormat lazy data object has *all* these properties, never a
+ // subset of them.
+ var lazyListFormatData = std_Object_create(null);
+
+ // Step 3.
+ var requestedLocales = CanonicalizeLocaleList(locales);
+ lazyListFormatData.requestedLocales = requestedLocales;
+
+ // Steps 4-5.
+ if (options === undefined) {
+ options = std_Object_create(null);
+ } else if (!IsObject(options)) {
+ ThrowTypeError(
+ JSMSG_OBJECT_REQUIRED,
+ options === null ? "null" : typeof options
+ );
+ }
+
+ // Step 6.
+ var opt = new_Record();
+ lazyListFormatData.opt = opt;
+
+ // Steps 7-8.
+ let matcher = GetOption(
+ options,
+ "localeMatcher",
+ "string",
+ ["lookup", "best fit"],
+ "best fit"
+ );
+ opt.localeMatcher = matcher;
+
+ // Compute formatting options.
+
+ // Steps 12-13.
+ var type = GetOption(
+ options,
+ "type",
+ "string",
+ ["conjunction", "disjunction", "unit"],
+ "conjunction"
+ );
+ lazyListFormatData.type = type;
+
+ // Steps 14-15.
+ var style = GetOption(
+ options,
+ "style",
+ "string",
+ ["long", "short", "narrow"],
+ "long"
+ );
+ lazyListFormatData.style = style;
+
+ // We've done everything that must be done now: mark the lazy data as fully
+ // computed and install it.
+ initializeIntlObject(listFormat, "ListFormat", lazyListFormatData);
+}
+
+/**
+ * Returns the subset of the given locale list for which this locale list has a
+ * matching (possibly fallback) locale. Locales appear in the same order in the
+ * returned list as in the input list.
+ */
+function Intl_ListFormat_supportedLocalesOf(locales /*, options*/) {
+ var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
+
+ // Step 1.
+ var availableLocales = "ListFormat";
+
+ // Step 2.
+ var requestedLocales = CanonicalizeLocaleList(locales);
+
+ // Step 3.
+ return SupportedLocales(availableLocales, requestedLocales, options);
+}
+
+/**
+ * StringListFromIterable ( iterable )
+ */
+function StringListFromIterable(iterable, methodName) {
+ // Step 1.
+ if (iterable === undefined) {
+ return [];
+ }
+
+ // Step 3.
+ var list = [];
+
+ // Steps 2, 4-5.
+ for (var element of allowContentIter(iterable)) {
+ // Step 5.b.ii.
+ if (typeof element !== "string") {
+ ThrowTypeError(
+ JSMSG_NOT_EXPECTED_TYPE,
+ methodName,
+ "string",
+ typeof element
+ );
+ }
+
+ // Step 5.b.iii.
+ DefineDataProperty(list, list.length, element);
+ }
+
+ // Step 6.
+ return list;
+}
+
+/**
+ * Intl.ListFormat.prototype.format ( list )
+ */
+function Intl_ListFormat_format(list) {
+ // Step 1.
+ var listFormat = this;
+
+ // Steps 2-3.
+ if (
+ !IsObject(listFormat) ||
+ (listFormat = intl_GuardToListFormat(listFormat)) === null
+ ) {
+ return callFunction(
+ intl_CallListFormatMethodIfWrapped,
+ this,
+ list,
+ "Intl_ListFormat_format"
+ );
+ }
+
+ // Step 4.
+ var stringList = StringListFromIterable(list, "format");
+
+ // We can directly return if |stringList| contains less than two elements.
+ if (stringList.length < 2) {
+ return stringList.length === 0 ? "" : stringList[0];
+ }
+
+ // Ensure the ListFormat internals are resolved.
+ getListFormatInternals(listFormat);
+
+ // Step 5.
+ return intl_FormatList(listFormat, stringList, /* formatToParts = */ false);
+}
+
+/**
+ * Intl.ListFormat.prototype.formatToParts ( list )
+ */
+function Intl_ListFormat_formatToParts(list) {
+ // Step 1.
+ var listFormat = this;
+
+ // Steps 2-3.
+ if (
+ !IsObject(listFormat) ||
+ (listFormat = intl_GuardToListFormat(listFormat)) === null
+ ) {
+ return callFunction(
+ intl_CallListFormatMethodIfWrapped,
+ this,
+ list,
+ "Intl_ListFormat_formatToParts"
+ );
+ }
+
+ // Step 4.
+ var stringList = StringListFromIterable(list, "formatToParts");
+
+ // We can directly return if |stringList| contains less than two elements.
+ if (stringList.length < 2) {
+ return stringList.length === 0
+ ? []
+ : [{ type: "element", value: stringList[0] }];
+ }
+
+ // Ensure the ListFormat internals are resolved.
+ getListFormatInternals(listFormat);
+
+ // Step 5.
+ return intl_FormatList(listFormat, stringList, /* formatToParts = */ true);
+}
+
+/**
+ * Returns the resolved options for a ListFormat object.
+ */
+function Intl_ListFormat_resolvedOptions() {
+ // Step 1.
+ var listFormat = this;
+
+ // Steps 2-3.
+ if (
+ !IsObject(listFormat) ||
+ (listFormat = intl_GuardToListFormat(listFormat)) === null
+ ) {
+ return callFunction(
+ intl_CallListFormatMethodIfWrapped,
+ this,
+ "Intl_ListFormat_resolvedOptions"
+ );
+ }
+
+ var internals = getListFormatInternals(listFormat);
+
+ // Steps 4-5.
+ var result = {
+ locale: internals.locale,
+ type: internals.type,
+ style: internals.style,
+ };
+
+ // Step 6.
+ return result;
+}