Source code

Revision control

Copy as Markdown

Other Tools

/* 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/. */
/* Portions Copyright Norbert Lindenberg 2011-2012. */
/**
* Compute an internal properties object from |lazyCollatorData|.
*/
function resolveCollatorInternals(lazyCollatorData) {
assert(IsObject(lazyCollatorData), "lazy data not an object?");
var internalProps = std_Object_create(null);
var Collator = collatorInternalProperties;
// Step 5.
internalProps.usage = lazyCollatorData.usage;
// Steps 6-7.
var collatorIsSorting = lazyCollatorData.usage === "sort";
var localeData = collatorIsSorting
? Collator.sortLocaleData
: Collator.searchLocaleData;
// Compute effective locale.
// Step 16.
var relevantExtensionKeys = Collator.relevantExtensionKeys;
// Step 17.
var r = ResolveLocale(
"Collator",
lazyCollatorData.requestedLocales,
lazyCollatorData.opt,
relevantExtensionKeys,
localeData
);
// Step 18.
internalProps.locale = r.locale;
// Step 19.
var collation = r.co;
// Step 20.
if (collation === null) {
collation = "default";
}
// Step 21.
internalProps.collation = collation;
// Step 22.
internalProps.numeric = r.kn === "true";
// Step 23.
internalProps.caseFirst = r.kf;
// Compute remaining collation options.
// Step 25.
var s = lazyCollatorData.rawSensitivity;
if (s === undefined) {
// In theory the default sensitivity for the "search" collator is
// locale dependent; in reality the CLDR/ICU default strength is
// always tertiary. Therefore use "variant" as the default value for
// both collation modes.
s = "variant";
}
// Step 26.
internalProps.sensitivity = s;
// Step 28.
var ignorePunctuation = lazyCollatorData.ignorePunctuation;
if (ignorePunctuation === undefined) {
var actualLocale = collatorActualLocale(r.dataLocale);
ignorePunctuation = intl_isIgnorePunctuation(actualLocale);
}
internalProps.ignorePunctuation = ignorePunctuation;
// The caller is responsible for associating |internalProps| with the right
// object using |setInternalProperties|.
return internalProps;
}
/**
* Returns an object containing the Collator internal properties of |obj|.
*/
function getCollatorInternals(obj) {
assert(IsObject(obj), "getCollatorInternals called with non-object");
assert(
intl_GuardToCollator(obj) !== null,
"getCollatorInternals called with non-Collator"
);
var internals = getIntlObjectInternals(obj);
assert(
internals.type === "Collator",
"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 = resolveCollatorInternals(internals.lazyData);
setInternalProperties(internals, internalProps);
return internalProps;
}
/**
* Initializes an object as a Collator.
*
* 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 Collator. This
* later work occurs in |resolveCollatorInternals|; steps not noted here occur
* there.
*
* Spec: ECMAScript Internationalization API Specification, 10.1.1.
*/
function InitializeCollator(collator, locales, options) {
assert(IsObject(collator), "InitializeCollator called with non-object");
assert(
intl_GuardToCollator(collator) !== null,
"InitializeCollator called with non-Collator"
);
// Lazy Collator data has the following structure:
//
// {
// requestedLocales: List of locales,
// usage: "sort" / "search",
// opt: // opt object computed in InitializeCollator
// {
// localeMatcher: "lookup" / "best fit",
// co: string matching a Unicode extension type / undefined
// kn: true / false / undefined,
// kf: "upper" / "lower" / "false" / undefined
// }
// rawSensitivity: "base" / "accent" / "case" / "variant" / undefined,
// ignorePunctuation: true / false / undefined
// }
//
// Note that lazy data is only installed as a final step of initialization,
// so every Collator lazy data object has *all* these properties, never a
// subset of them.
var lazyCollatorData = std_Object_create(null);
// Step 1.
var requestedLocales = CanonicalizeLocaleList(locales);
lazyCollatorData.requestedLocales = requestedLocales;
// Steps 2-3.
//
// If we ever need more speed here at startup, we should try to detect the
// case where |options === undefined| and then directly use the default
// value for each option. For now, just keep it simple.
if (options === undefined) {
options = std_Object_create(null);
} else {
options = ToObject(options);
}
// Compute options that impact interpretation of locale.
// Step 4.
var u = GetOption(options, "usage", "string", ["sort", "search"], "sort");
lazyCollatorData.usage = u;
// Step 8.
var opt = new_Record();
lazyCollatorData.opt = opt;
// Steps 9-10.
var matcher = GetOption(
options,
"localeMatcher",
"string",
["lookup", "best fit"],
"best fit"
);
opt.localeMatcher = matcher;
var collation = GetOption(
options,
"collation",
"string",
undefined,
undefined
);
if (collation !== undefined) {
collation = intl_ValidateAndCanonicalizeUnicodeExtensionType(
collation,
"collation",
"co"
);
}
opt.co = collation;
// Steps 11-13.
var numericValue = GetOption(
options,
"numeric",
"boolean",
undefined,
undefined
);
if (numericValue !== undefined) {
numericValue = numericValue ? "true" : "false";
}
opt.kn = numericValue;
// Steps 14-15.
var caseFirstValue = GetOption(
options,
"caseFirst",
"string",
["upper", "lower", "false"],
undefined
);
opt.kf = caseFirstValue;
// Compute remaining collation options.
// Step 24.
var s = GetOption(
options,
"sensitivity",
"string",
["base", "accent", "case", "variant"],
undefined
);
lazyCollatorData.rawSensitivity = s;
// Step 27.
var ip = GetOption(options, "ignorePunctuation", "boolean", undefined, undefined);
lazyCollatorData.ignorePunctuation = ip;
// Step 29.
//
// We've done everything that must be done now: mark the lazy data as fully
// computed and install it.
initializeIntlObject(collator, "Collator", lazyCollatorData);
}
/**
* 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.
*
* Spec: ECMAScript Internationalization API Specification, 10.2.2.
*/
function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined;
// Step 1.
var availableLocales = "Collator";
// Step 2.
var requestedLocales = CanonicalizeLocaleList(locales);
// Step 3.
return SupportedLocales(availableLocales, requestedLocales, options);
}
/**
* Collator internal properties.
*
* Spec: ECMAScript Internationalization API Specification, 9.1 and 10.2.3.
*/
var collatorInternalProperties = {
sortLocaleData: collatorSortLocaleData,
searchLocaleData: collatorSearchLocaleData,
relevantExtensionKeys: ["co", "kf", "kn"],
};
/**
* Returns the actual locale used when a collator for |locale| is constructed.
*/
function collatorActualLocale(locale) {
assert(typeof locale === "string", "locale should be string");
// If |locale| is the default locale (e.g. da-DK), but only supported
// through a fallback (da), we need to get the actual locale before we
// can call intl_isUpperCaseFirst. Also see intl_BestAvailableLocale.
return BestAvailableLocaleIgnoringDefault("Collator", locale);
}
/**
* Returns the default caseFirst values for the given locale. The first
* element in the returned array denotes the default value per ES2017 Intl,
* 9.1 Internal slots of Service Constructors.
*/
function collatorSortCaseFirst(locale) {
var actualLocale = collatorActualLocale(locale);
if (intl_isUpperCaseFirst(actualLocale)) {
return ["upper", "false", "lower"];
}
// Default caseFirst values for all other languages.
return ["false", "lower", "upper"];
}
/**
* Returns the default caseFirst value for the given locale.
*/
function collatorSortCaseFirstDefault(locale) {
var actualLocale = collatorActualLocale(locale);
if (intl_isUpperCaseFirst(actualLocale)) {
return "upper";
}
// Default caseFirst value for all other languages.
return "false";
}
function collatorSortLocaleData() {
/* eslint-disable object-shorthand */
return {
co: intl_availableCollations,
kn: function() {
return ["false", "true"];
},
kf: collatorSortCaseFirst,
default: {
co: function() {
// The first element of the collations array must be |null|
// per ES2017 Intl, 10.2.3 Internal Slots.
return null;
},
kn: function() {
return "false";
},
kf: collatorSortCaseFirstDefault,
},
};
/* eslint-enable object-shorthand */
}
function collatorSearchLocaleData() {
/* eslint-disable object-shorthand */
return {
co: function() {
return [null];
},
kn: function() {
return ["false", "true"];
},
kf: function() {
return ["false", "lower", "upper"];
},
default: {
co: function() {
return null;
},
kn: function() {
return "false";
},
kf: function() {
return "false";
},
},
};
/* eslint-enable object-shorthand */
}
/**
* Create function to be cached and returned by Intl.Collator.prototype.compare.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.3.1.
*/
function createCollatorCompare(collator) {
// This function is not inlined in $Intl_Collator_compare_get to avoid
// creating a call-object on each call to $Intl_Collator_compare_get.
return function(x, y) {
// Step 1 (implicit).
// Step 2.
assert(IsObject(collator), "collatorCompareToBind called with non-object");
assert(
intl_GuardToCollator(collator) !== null,
"collatorCompareToBind called with non-Collator"
);
// Steps 3-6
var X = ToString(x);
var Y = ToString(y);
// Step 7.
return intl_CompareStrings(collator, X, Y);
};
}
/**
* Returns a function bound to this Collator that compares x (converted to a
* String value) and y (converted to a String value),
* and returns a number less than 0 if x < y, 0 if x = y, or a number greater
* than 0 if x > y according to the sort order for the locale and collation
* options of this Collator object.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.3.
*/
// Uncloned functions with `$` prefix are allocated as extended function
// to store the original name in `SetCanonicalName`.
function $Intl_Collator_compare_get() {
// Step 1.
var collator = this;
// Steps 2-3.
if (
!IsObject(collator) ||
(collator = intl_GuardToCollator(collator)) === null
) {
return callFunction(
intl_CallCollatorMethodIfWrapped,
this,
"$Intl_Collator_compare_get"
);
}
var internals = getCollatorInternals(collator);
// Step 4.
if (internals.boundCompare === undefined) {
// Steps 4.a-c.
internals.boundCompare = createCollatorCompare(collator);
}
// Step 5.
return internals.boundCompare;
}
SetCanonicalName($Intl_Collator_compare_get, "get compare");
/**
* Returns the resolved options for a Collator object.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.4.
*/
function Intl_Collator_resolvedOptions() {
// Step 1.
var collator = this;
// Steps 2-3.
if (
!IsObject(collator) ||
(collator = intl_GuardToCollator(collator)) === null
) {
return callFunction(
intl_CallCollatorMethodIfWrapped,
this,
"Intl_Collator_resolvedOptions"
);
}
var internals = getCollatorInternals(collator);
// Steps 4-5.
var result = {
locale: internals.locale,
usage: internals.usage,
sensitivity: internals.sensitivity,
ignorePunctuation: internals.ignorePunctuation,
collation: internals.collation,
numeric: internals.numeric,
caseFirst: internals.caseFirst,
};
// Step 6.
return result;
}