blob: b1b26cefbf9e3c9bded273f960a430c7b737b362 [file] [log] [blame]
// Copyright (C) 2011 2012 Norbert Lindenberg. All rights reserved.
// Copyright (C) 2012 2013 Mozilla Corporation. All rights reserved.
// Copyright (C) 2020 Apple Inc. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: |
This file contains shared functions for the tests in the conformance test
suite for the ECMAScript Internationalization API.
author: Norbert Lindenberg
defines:
- testWithIntlConstructors
- taintDataProperty
- taintMethod
- taintProperties
- taintArray
- getLocaleSupportInfo
- getInvalidLanguageTags
- isCanonicalizedStructurallyValidLanguageTag
- getInvalidLocaleArguments
- testOption
- testForUnwantedRegExpChanges
- allCalendars
- allCollations
- allNumberingSystems
- isValidNumberingSystem
- numberingSystemDigits
- allSimpleSanctionedUnits
- testNumberFormat
- getDateTimeComponents
- getDateTimeComponentValues
- isCanonicalizedStructurallyValidTimeZoneName
---*/
/**
*/
/**
* @description Calls the provided function for every service constructor in
* the Intl object.
* @param {Function} f the function to call for each service constructor in
* the Intl object.
* @param {Function} Constructor the constructor object to test with.
*/
function testWithIntlConstructors(f) {
var constructors = ["Collator", "NumberFormat", "DateTimeFormat"];
// Optionally supported Intl constructors.
// NB: Intl.Locale isn't an Intl service constructor!
// Intl.DisplayNames cannot be called without type in options.
["PluralRules", "RelativeTimeFormat", "ListFormat"].forEach(function(constructor) {
if (typeof Intl[constructor] === "function") {
constructors[constructors.length] = constructor;
}
});
constructors.forEach(function (constructor) {
var Constructor = Intl[constructor];
try {
f(Constructor);
} catch (e) {
e.message += " (Testing with " + constructor + ".)";
throw e;
}
});
}
/**
* Taints a named data property of the given object by installing
* a setter that throws an exception.
* @param {object} obj the object whose data property to taint
* @param {string} property the property to taint
*/
function taintDataProperty(obj, property) {
Object.defineProperty(obj, property, {
set: function(value) {
throw new Test262Error("Client code can adversely affect behavior: setter for " + property + ".");
},
enumerable: false,
configurable: true
});
}
/**
* Taints a named method of the given object by replacing it with a function
* that throws an exception.
* @param {object} obj the object whose method to taint
* @param {string} property the name of the method to taint
*/
function taintMethod(obj, property) {
Object.defineProperty(obj, property, {
value: function() {
throw new Test262Error("Client code can adversely affect behavior: method " + property + ".");
},
writable: true,
enumerable: false,
configurable: true
});
}
/**
* Taints the given properties (and similarly named properties) by installing
* setters on Object.prototype that throw exceptions.
* @param {Array} properties an array of property names to taint
*/
function taintProperties(properties) {
properties.forEach(function (property) {
var adaptedProperties = [property, "__" + property, "_" + property, property + "_", property + "__"];
adaptedProperties.forEach(function (property) {
taintDataProperty(Object.prototype, property);
});
});
}
/**
* Taints the Array object by creating a setter for the property "0" and
* replacing some key methods with functions that throw exceptions.
*/
function taintArray() {
taintDataProperty(Array.prototype, "0");
taintMethod(Array.prototype, "indexOf");
taintMethod(Array.prototype, "join");
taintMethod(Array.prototype, "push");
taintMethod(Array.prototype, "slice");
taintMethod(Array.prototype, "sort");
}
/**
* Gets locale support info for the given constructor object, which must be one
* of Intl constructors.
* @param {object} Constructor the constructor for which to get locale support info
* @param {object} options the options while calling the constructor
* @return {object} locale support info with the following properties:
* supported: array of fully supported language tags
* byFallback: array of language tags that are supported through fallbacks
* unsupported: array of unsupported language tags
*/
function getLocaleSupportInfo(Constructor, options) {
var languages = ["zh", "es", "en", "hi", "ur", "ar", "ja", "pa"];
var scripts = ["Latn", "Hans", "Deva", "Arab", "Jpan", "Hant", "Guru"];
var countries = ["CN", "IN", "US", "PK", "JP", "TW", "HK", "SG", "419"];
var allTags = [];
var i, j, k;
var language, script, country;
for (i = 0; i < languages.length; i++) {
language = languages[i];
allTags.push(language);
for (j = 0; j < scripts.length; j++) {
script = scripts[j];
allTags.push(language + "-" + script);
for (k = 0; k < countries.length; k++) {
country = countries[k];
allTags.push(language + "-" + script + "-" + country);
}
}
for (k = 0; k < countries.length; k++) {
country = countries[k];
allTags.push(language + "-" + country);
}
}
var supported = [];
var byFallback = [];
var unsupported = [];
for (i = 0; i < allTags.length; i++) {
var request = allTags[i];
var result = new Constructor([request], options).resolvedOptions().locale;
if (request === result) {
supported.push(request);
} else if (request.indexOf(result) === 0) {
byFallback.push(request);
} else {
unsupported.push(request);
}
}
return {
supported: supported,
byFallback: byFallback,
unsupported: unsupported
};
}
/**
* Returns an array of strings for which IsStructurallyValidLanguageTag() returns false
*/
function getInvalidLanguageTags() {
var invalidLanguageTags = [
"", // empty tag
"i", // singleton alone
"x", // private use without subtag
"u", // extension singleton in first place
"419", // region code in first place
"u-nu-latn-cu-bob", // extension sequence without language
"hans-cmn-cn", // "hans" could theoretically be a 4-letter language code,
// but those can't be followed by extlang codes.
"cmn-hans-cn-u-u", // duplicate singleton
"cmn-hans-cn-t-u-ca-u", // duplicate singleton
"de-gregory-gregory", // duplicate variant
"*", // language range
"de-*", // language range
"中文", // non-ASCII letters
"en-ß", // non-ASCII letters
"ıd", // non-ASCII letters
"es-Latn-latn", // two scripts
"pl-PL-pl", // two regions
"u-ca-gregory", // extension in first place
"de-1996-1996", // duplicate numeric variant
"pt-u-ca-gregory-u-nu-latn", // duplicate singleton subtag
// Invalid tags starting with: https://github.com/tc39/ecma402/pull/289
"no-nyn", // regular grandfathered in BCP47, but invalid in UTS35
"i-klingon", // irregular grandfathered in BCP47, but invalid in UTS35
"zh-hak-CN", // language with extlang in BCP47, but invalid in UTS35
"sgn-ils", // language with extlang in BCP47, but invalid in UTS35
"x-foo", // privateuse-only in BCP47, but invalid in UTS35
"x-en-US-12345", // more privateuse-only variants.
"x-12345-12345-en-US",
"x-en-US-12345-12345",
"x-en-u-foo",
"x-en-u-foo-u-bar",
"x-u-foo",
// underscores in different parts of the language tag
"de_DE",
"DE_de",
"cmn_Hans",
"cmn-hans_cn",
"es_419",
"es-419-u-nu-latn-cu_bob",
"i_klingon",
"cmn-hans-cn-t-ca-u-ca-x_t-u",
"enochian_enochian",
"de-gregory_u-ca-gregory",
"en\u0000", // null-terminator sequence
" en", // leading whitespace
"en ", // trailing whitespace
"it-IT-Latn", // country before script tag
"de-u", // incomplete Unicode extension sequences
"de-u-",
"de-u-ca-",
"de-u-ca-gregory-",
"si-x", // incomplete private-use tags
"x-",
"x-y-",
];
// make sure the data above is correct
for (var i = 0; i < invalidLanguageTags.length; ++i) {
var invalidTag = invalidLanguageTags[i];
assert(
!isCanonicalizedStructurallyValidLanguageTag(invalidTag),
"Test data \"" + invalidTag + "\" is a canonicalized and structurally valid language tag."
);
}
return invalidLanguageTags;
}
/**
* @description Tests whether locale is a String value representing a
* structurally valid and canonicalized BCP 47 language tag, as defined in
* sections 6.2.2 and 6.2.3 of the ECMAScript Internationalization API
* Specification.
* @param {String} locale the string to be tested.
* @result {Boolean} whether the test succeeded.
*/
function isCanonicalizedStructurallyValidLanguageTag(locale) {
/**
* Regular expression defining Unicode BCP 47 Locale Identifiers.
*
* Spec: https://unicode.org/reports/tr35/#Unicode_locale_identifier
*/
var alpha = "[a-z]",
digit = "[0-9]",
alphanum = "[a-z0-9]",
variant = "(" + alphanum + "{5,8}|(?:" + digit + alphanum + "{3}))",
region = "(" + alpha + "{2}|" + digit + "{3})",
script = "(" + alpha + "{4})",
language = "(" + alpha + "{2,3}|" + alpha + "{5,8})",
privateuse = "(x(-[a-z0-9]{1,8})+)",
singleton = "(" + digit + "|[a-wy-z])",
attribute= "(" + alphanum + "{3,8})",
keyword = "(" + alphanum + alpha + "(-" + alphanum + "{3,8})*)",
unicode_locale_extensions = "(u((-" + keyword + ")+|((-" + attribute + ")+(-" + keyword + ")*)))",
tlang = "(" + language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*)",
tfield = "(" + alpha + digit + "(-" + alphanum + "{3,8})+)",
transformed_extensions = "(t((-" + tlang + "(-" + tfield + ")*)|(-" + tfield + ")+))",
other_singleton = "(" + digit + "|[a-sv-wy-z])",
other_extensions = "(" + other_singleton + "(-" + alphanum + "{2,8})+)",
extension = "(" + unicode_locale_extensions + "|" + transformed_extensions + "|" + other_extensions + ")",
locale_id = language + "(-" + script + ")?(-" + region + ")?(-" + variant + ")*(-" + extension + ")*(-" + privateuse + ")?",
languageTag = "^(" + locale_id + ")$",
languageTagRE = new RegExp(languageTag, "i");
var duplicateSingleton = "-" + singleton + "-(.*-)?\\1(?!" + alphanum + ")",
duplicateSingletonRE = new RegExp(duplicateSingleton, "i"),
duplicateVariant = "(" + alphanum + "{2,8}-)+" + variant + "-(" + alphanum + "{2,8}-)*\\2(?!" + alphanum + ")",
duplicateVariantRE = new RegExp(duplicateVariant, "i");
var transformKeyRE = new RegExp("^" + alpha + digit + "$", "i");
/**
* Verifies that the given string is a well-formed Unicode BCP 47 Locale Identifier
* with no duplicate variant or singleton subtags.
*
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.2.
*/
function isStructurallyValidLanguageTag(locale) {
if (!languageTagRE.test(locale)) {
return false;
}
locale = locale.split(/-x-/)[0];
return !duplicateSingletonRE.test(locale) && !duplicateVariantRE.test(locale);
}
/**
* Mappings from complete tags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __tagMappings = {
// property names must be in lower case; values in canonical form
"art-lojban": "jbo",
"cel-gaulish": "xtg",
"zh-guoyu": "zh",
"zh-hakka": "hak",
"zh-xiang": "hsn",
};
/**
* Mappings from language subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __languageMappings = {
// property names and values must be in canonical case
"aam": "aas",
"aar": "aa",
"abk": "ab",
"adp": "dz",
"afr": "af",
"aju": "jrb",
"aka": "ak",
"alb": "sq",
"als": "sq",
"amh": "am",
"ara": "ar",
"arb": "ar",
"arg": "an",
"arm": "hy",
"asd": "snz",
"asm": "as",
"aue": "ktz",
"ava": "av",
"ave": "ae",
"aym": "ay",
"ayr": "ay",
"ayx": "nun",
"aze": "az",
"azj": "az",
"bak": "ba",
"bam": "bm",
"baq": "eu",
"bcc": "bal",
"bcl": "bik",
"bel": "be",
"ben": "bn",
"bgm": "bcg",
"bh": "bho",
"bih": "bho",
"bis": "bi",
"bjd": "drl",
"bod": "bo",
"bos": "bs",
"bre": "br",
"bul": "bg",
"bur": "my",
"bxk": "luy",
"bxr": "bua",
"cat": "ca",
"ccq": "rki",
"ces": "cs",
"cha": "ch",
"che": "ce",
"chi": "zh",
"chu": "cu",
"chv": "cv",
"cjr": "mom",
"cka": "cmr",
"cld": "syr",
"cmk": "xch",
"cmn": "zh",
"cor": "kw",
"cos": "co",
"coy": "pij",
"cqu": "quh",
"cre": "cr",
"cwd": "cr",
"cym": "cy",
"cze": "cs",
"dan": "da",
"deu": "de",
"dgo": "doi",
"dhd": "mwr",
"dik": "din",
"diq": "zza",
"dit": "dif",
"div": "dv",
"drh": "mn",
"dut": "nl",
"dzo": "dz",
"ekk": "et",
"ell": "el",
"emk": "man",
"eng": "en",
"epo": "eo",
"esk": "ik",
"est": "et",
"eus": "eu",
"ewe": "ee",
"fao": "fo",
"fas": "fa",
"fat": "ak",
"fij": "fj",
"fin": "fi",
"fra": "fr",
"fre": "fr",
"fry": "fy",
"fuc": "ff",
"ful": "ff",
"gav": "dev",
"gaz": "om",
"gbo": "grb",
"geo": "ka",
"ger": "de",
"gfx": "vaj",
"ggn": "gvr",
"gla": "gd",
"gle": "ga",
"glg": "gl",
"glv": "gv",
"gno": "gon",
"gre": "el",
"grn": "gn",
"gti": "nyc",
"gug": "gn",
"guj": "gu",
"guv": "duz",
"gya": "gba",
"hat": "ht",
"hau": "ha",
"hdn": "hai",
"hea": "hmn",
"heb": "he",
"her": "hz",
"him": "srx",
"hin": "hi",
"hmo": "ho",
"hrr": "jal",
"hrv": "hr",
"hun": "hu",
"hye": "hy",
"ibi": "opa",
"ibo": "ig",
"ice": "is",
"ido": "io",
"iii": "ii",
"ike": "iu",
"iku": "iu",
"ile": "ie",
"ilw": "gal",
"in": "id",
"ina": "ia",
"ind": "id",
"ipk": "ik",
"isl": "is",
"ita": "it",
"iw": "he",
"jav": "jv",
"jeg": "oyb",
"ji": "yi",
"jpn": "ja",
"jw": "jv",
"kal": "kl",
"kan": "kn",
"kas": "ks",
"kat": "ka",
"kau": "kr",
"kaz": "kk",
"kgc": "tdf",
"kgh": "kml",
"khk": "mn",
"khm": "km",
"kik": "ki",
"kin": "rw",
"kir": "ky",
"kmr": "ku",
"knc": "kr",
"kng": "kg",
"knn": "kok",
"koj": "kwv",
"kom": "kv",
"kon": "kg",
"kor": "ko",
"kpv": "kv",
"krm": "bmf",
"ktr": "dtp",
"kua": "kj",
"kur": "ku",
"kvs": "gdj",
"kwq": "yam",
"kxe": "tvd",
"kzj": "dtp",
"kzt": "dtp",
"lao": "lo",
"lat": "la",
"lav": "lv",
"lbk": "bnc",
"lii": "raq",
"lim": "li",
"lin": "ln",
"lit": "lt",
"llo": "ngt",
"lmm": "rmx",
"ltz": "lb",
"lub": "lu",
"lug": "lg",
"lvs": "lv",
"mac": "mk",
"mah": "mh",
"mal": "ml",
"mao": "mi",
"mar": "mr",
"may": "ms",
"meg": "cir",
"mhr": "chm",
"mkd": "mk",
"mlg": "mg",
"mlt": "mt",
"mnk": "man",
"mo": "ro",
"mol": "ro",
"mon": "mn",
"mri": "mi",
"msa": "ms",
"mst": "mry",
"mup": "raj",
"mwj": "vaj",
"mya": "my",
"myd": "aog",
"myt": "mry",
"nad": "xny",
"nau": "na",
"nav": "nv",
"nbl": "nr",
"ncp": "kdz",
"nde": "nd",
"ndo": "ng",
"nep": "ne",
"nld": "nl",
"nno": "nn",
"nns": "nbr",
"nnx": "ngv",
"no": "nb",
"nob": "nb",
"nor": "nb",
"npi": "ne",
"nts": "pij",
"nya": "ny",
"oci": "oc",
"ojg": "oj",
"oji": "oj",
"ori": "or",
"orm": "om",
"ory": "or",
"oss": "os",
"oun": "vaj",
"pan": "pa",
"pbu": "ps",
"pcr": "adx",
"per": "fa",
"pes": "fa",
"pli": "pi",
"plt": "mg",
"pmc": "huw",
"pmu": "phr",
"pnb": "lah",
"pol": "pl",
"por": "pt",
"ppa": "bfy",
"ppr": "lcq",
"pry": "prt",
"pus": "ps",
"puz": "pub",
"que": "qu",
"quz": "qu",
"rmy": "rom",
"roh": "rm",
"ron": "ro",
"rum": "ro",
"run": "rn",
"rus": "ru",
"sag": "sg",
"san": "sa",
"sca": "hle",
"scc": "sr",
"scr": "hr",
"sin": "si",
"skk": "oyb",
"slk": "sk",
"slo": "sk",
"slv": "sl",
"sme": "se",
"smo": "sm",
"sna": "sn",
"snd": "sd",
"som": "so",
"sot": "st",
"spa": "es",
"spy": "kln",
"sqi": "sq",
"src": "sc",
"srd": "sc",
"srp": "sr",
"ssw": "ss",
"sun": "su",
"swa": "sw",
"swe": "sv",
"swh": "sw",
"tah": "ty",
"tam": "ta",
"tat": "tt",
"tdu": "dtp",
"tel": "te",
"tgk": "tg",
"tgl": "fil",
"tha": "th",
"thc": "tpo",
"thx": "oyb",
"tib": "bo",
"tie": "ras",
"tir": "ti",
"tkk": "twm",
"tl": "fil",
"tlw": "weo",
"tmp": "tyj",
"tne": "kak",
"ton": "to",
"tsf": "taj",
"tsn": "tn",
"tso": "ts",
"ttq": "tmh",
"tuk": "tk",
"tur": "tr",
"tw": "ak",
"twi": "ak",
"uig": "ug",
"ukr": "uk",
"umu": "del",
"uok": "ema",
"urd": "ur",
"uzb": "uz",
"uzn": "uz",
"ven": "ve",
"vie": "vi",
"vol": "vo",
"wel": "cy",
"wln": "wa",
"wol": "wo",
"xba": "cax",
"xho": "xh",
"xia": "acn",
"xkh": "waw",
"xpe": "kpe",
"xsj": "suj",
"xsl": "den",
"ybd": "rki",
"ydd": "yi",
"yid": "yi",
"yma": "lrr",
"ymt": "mtm",
"yor": "yo",
"yos": "zom",
"yuu": "yug",
"zai": "zap",
"zha": "za",
"zho": "zh",
"zsm": "ms",
"zul": "zu",
"zyb": "za",
};
/**
* Mappings from region subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __regionMappings = {
// property names and values must be in canonical case
"004": "AF",
"008": "AL",
"010": "AQ",
"012": "DZ",
"016": "AS",
"020": "AD",
"024": "AO",
"028": "AG",
"031": "AZ",
"032": "AR",
"036": "AU",
"040": "AT",
"044": "BS",
"048": "BH",
"050": "BD",
"051": "AM",
"052": "BB",
"056": "BE",
"060": "BM",
"062": "034",
"064": "BT",
"068": "BO",
"070": "BA",
"072": "BW",
"074": "BV",
"076": "BR",
"084": "BZ",
"086": "IO",
"090": "SB",
"092": "VG",
"096": "BN",
"100": "BG",
"104": "MM",
"108": "BI",
"112": "BY",
"116": "KH",
"120": "CM",
"124": "CA",
"132": "CV",
"136": "KY",
"140": "CF",
"144": "LK",
"148": "TD",
"152": "CL",
"156": "CN",
"158": "TW",
"162": "CX",
"166": "CC",
"170": "CO",
"174": "KM",
"175": "YT",
"178": "CG",
"180": "CD",
"184": "CK",
"188": "CR",
"191": "HR",
"192": "CU",
"196": "CY",
"203": "CZ",
"204": "BJ",
"208": "DK",
"212": "DM",
"214": "DO",
"218": "EC",
"222": "SV",
"226": "GQ",
"230": "ET",
"231": "ET",
"232": "ER",
"233": "EE",
"234": "FO",
"238": "FK",
"239": "GS",
"242": "FJ",
"246": "FI",
"248": "AX",
"249": "FR",
"250": "FR",
"254": "GF",
"258": "PF",
"260": "TF",
"262": "DJ",
"266": "GA",
"268": "GE",
"270": "GM",
"275": "PS",
"276": "DE",
"278": "DE",
"280": "DE",
"288": "GH",
"292": "GI",
"296": "KI",
"300": "GR",
"304": "GL",
"308": "GD",
"312": "GP",
"316": "GU",
"320": "GT",
"324": "GN",
"328": "GY",
"332": "HT",
"334": "HM",
"336": "VA",
"340": "HN",
"344": "HK",
"348": "HU",
"352": "IS",
"356": "IN",
"360": "ID",
"364": "IR",
"368": "IQ",
"372": "IE",
"376": "IL",
"380": "IT",
"384": "CI",
"388": "JM",
"392": "JP",
"398": "KZ",
"400": "JO",
"404": "KE",
"408": "KP",
"410": "KR",
"414": "KW",
"417": "KG",
"418": "LA",
"422": "LB",
"426": "LS",
"428": "LV",
"430": "LR",
"434": "LY",
"438": "LI",
"440": "LT",
"442": "LU",
"446": "MO",
"450": "MG",
"454": "MW",
"458": "MY",
"462": "MV",
"466": "ML",
"470": "MT",
"474": "MQ",
"478": "MR",
"480": "MU",
"484": "MX",
"492": "MC",
"496": "MN",
"498": "MD",
"499": "ME",
"500": "MS",
"504": "MA",
"508": "MZ",
"512": "OM",
"516": "NA",
"520": "NR",
"524": "NP",
"528": "NL",
"531": "CW",
"533": "AW",
"534": "SX",
"535": "BQ",
"540": "NC",
"548": "VU",
"554": "NZ",
"558": "NI",
"562": "NE",
"566": "NG",
"570": "NU",
"574": "NF",
"578": "NO",
"580": "MP",
"581": "UM",
"583": "FM",
"584": "MH",
"585": "PW",
"586": "PK",
"591": "PA",
"598": "PG",
"600": "PY",
"604": "PE",
"608": "PH",
"612": "PN",
"616": "PL",
"620": "PT",
"624": "GW",
"626": "TL",
"630": "PR",
"634": "QA",
"638": "RE",
"642": "RO",
"643": "RU",
"646": "RW",
"652": "BL",
"654": "SH",
"659": "KN",
"660": "AI",
"662": "LC",
"663": "MF",
"666": "PM",
"670": "VC",
"674": "SM",
"678": "ST",
"682": "SA",
"686": "SN",
"688": "RS",
"690": "SC",
"694": "SL",
"702": "SG",
"703": "SK",
"704": "VN",
"705": "SI",
"706": "SO",
"710": "ZA",
"716": "ZW",
"720": "YE",
"724": "ES",
"728": "SS",
"729": "SD",
"732": "EH",
"736": "SD",
"740": "SR",
"744": "SJ",
"748": "SZ",
"752": "SE",
"756": "CH",
"760": "SY",
"762": "TJ",
"764": "TH",
"768": "TG",
"772": "TK",
"776": "TO",
"780": "TT",
"784": "AE",
"788": "TN",
"792": "TR",
"795": "TM",
"796": "TC",
"798": "TV",
"800": "UG",
"804": "UA",
"807": "MK",
"818": "EG",
"826": "GB",
"830": "JE",
"831": "GG",
"832": "JE",
"833": "IM",
"834": "TZ",
"840": "US",
"850": "VI",
"854": "BF",
"858": "UY",
"860": "UZ",
"862": "VE",
"876": "WF",
"882": "WS",
"886": "YE",
"887": "YE",
"891": "RS",
"894": "ZM",
"958": "AA",
"959": "QM",
"960": "QN",
"962": "QP",
"963": "QQ",
"964": "QR",
"965": "QS",
"966": "QT",
"967": "EU",
"968": "QV",
"969": "QW",
"970": "QX",
"971": "QY",
"972": "QZ",
"973": "XA",
"974": "XB",
"975": "XC",
"976": "XD",
"977": "XE",
"978": "XF",
"979": "XG",
"980": "XH",
"981": "XI",
"982": "XJ",
"983": "XK",
"984": "XL",
"985": "XM",
"986": "XN",
"987": "XO",
"988": "XP",
"989": "XQ",
"990": "XR",
"991": "XS",
"992": "XT",
"993": "XU",
"994": "XV",
"995": "XW",
"996": "XX",
"997": "XY",
"998": "XZ",
"999": "ZZ",
"BU": "MM",
"CS": "RS",
"CT": "KI",
"DD": "DE",
"DY": "BJ",
"FQ": "AQ",
"FX": "FR",
"HV": "BF",
"JT": "UM",
"MI": "UM",
"NH": "VU",
"NQ": "AQ",
"PU": "UM",
"PZ": "PA",
"QU": "EU",
"RH": "ZW",
"TP": "TL",
"UK": "GB",
"VD": "VN",
"WK": "UM",
"YD": "YE",
"YU": "RS",
"ZR": "CD",
};
/**
* Complex mappings from language subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __complexLanguageMappings = {
// property names and values must be in canonical case
"cnr": {language: "sr", region: "ME"},
"drw": {language: "fa", region: "AF"},
"hbs": {language: "sr", script: "Latn"},
"prs": {language: "fa", region: "AF"},
"sh": {language: "sr", script: "Latn"},
"swc": {language: "sw", region: "CD"},
"tnf": {language: "fa", region: "AF"},
};
/**
* Complex mappings from region subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __complexRegionMappings = {
// property names and values must be in canonical case
"172": {
default: "RU",
"ab": "GE",
"az": "AZ",
"be": "BY",
"crh": "UA",
"gag": "MD",
"got": "UA",
"hy": "AM",
"ji": "UA",
"ka": "GE",
"kaa": "UZ",
"kk": "KZ",
"ku-Yezi": "GE",
"ky": "KG",
"os": "GE",
"rue": "UA",
"sog": "UZ",
"tg": "TJ",
"tk": "TM",
"tkr": "AZ",
"tly": "AZ",
"ttt": "AZ",
"ug-Cyrl": "KZ",
"uk": "UA",
"und-Armn": "AM",
"und-Chrs": "UZ",
"und-Geor": "GE",
"und-Goth": "UA",
"und-Sogd": "UZ",
"und-Sogo": "UZ",
"und-Yezi": "GE",
"uz": "UZ",
"xco": "UZ",
"xmf": "GE",
},
"200": {
default: "CZ",
"sk": "SK",
},
"530": {
default: "CW",
"vic": "SX",
},
"532": {
default: "CW",
"vic": "SX",
},
"536": {
default: "SA",
"akk": "IQ",
"ckb": "IQ",
"ku-Arab": "IQ",
"mis": "IQ",
"syr": "IQ",
"und-Hatr": "IQ",
"und-Syrc": "IQ",
"und-Xsux": "IQ",
},
"582": {
default: "FM",
"mh": "MH",
"pau": "PW",
},
"810": {
default: "RU",
"ab": "GE",
"az": "AZ",
"be": "BY",
"crh": "UA",
"et": "EE",
"gag": "MD",
"got": "UA",
"hy": "AM",
"ji": "UA",
"ka": "GE",
"kaa": "UZ",
"kk": "KZ",
"ku-Yezi": "GE",
"ky": "KG",
"lt": "LT",
"ltg": "LV",
"lv": "LV",
"os": "GE",
"rue": "UA",
"sgs": "LT",
"sog": "UZ",
"tg": "TJ",
"tk": "TM",
"tkr": "AZ",
"tly": "AZ",
"ttt": "AZ",
"ug-Cyrl": "KZ",
"uk": "UA",
"und-Armn": "AM",
"und-Chrs": "UZ",
"und-Geor": "GE",
"und-Goth": "UA",
"und-Sogd": "UZ",
"und-Sogo": "UZ",
"und-Yezi": "GE",
"uz": "UZ",
"vro": "EE",
"xco": "UZ",
"xmf": "GE",
},
"890": {
default: "RS",
"bs": "BA",
"hr": "HR",
"mk": "MK",
"sl": "SI",
},
"AN": {
default: "CW",
"vic": "SX",
},
"NT": {
default: "SA",
"akk": "IQ",
"ckb": "IQ",
"ku-Arab": "IQ",
"mis": "IQ",
"syr": "IQ",
"und-Hatr": "IQ",
"und-Syrc": "IQ",
"und-Xsux": "IQ",
},
"PC": {
default: "FM",
"mh": "MH",
"pau": "PW",
},
"SU": {
default: "RU",
"ab": "GE",
"az": "AZ",
"be": "BY",
"crh": "UA",
"et": "EE",
"gag": "MD",
"got": "UA",
"hy": "AM",
"ji": "UA",
"ka": "GE",
"kaa": "UZ",
"kk": "KZ",
"ku-Yezi": "GE",
"ky": "KG",
"lt": "LT",
"ltg": "LV",
"lv": "LV",
"os": "GE",
"rue": "UA",
"sgs": "LT",
"sog": "UZ",
"tg": "TJ",
"tk": "TM",
"tkr": "AZ",
"tly": "AZ",
"ttt": "AZ",
"ug-Cyrl": "KZ",
"uk": "UA",
"und-Armn": "AM",
"und-Chrs": "UZ",
"und-Geor": "GE",
"und-Goth": "UA",
"und-Sogd": "UZ",
"und-Sogo": "UZ",
"und-Yezi": "GE",
"uz": "UZ",
"vro": "EE",
"xco": "UZ",
"xmf": "GE",
},
};
/**
* Mappings from variant subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __variantMappings = {
// property names and values must be in canonical case
"aaland": {type: "region", replacement: "AX"},
"arevela": {type: "language", replacement: "hy"},
"arevmda": {type: "language", replacement: "hyw"},
"heploc": {type: "variant", replacement: "alalc97"},
"polytoni": {type: "variant", replacement: "polyton"},
};
/**
* Mappings from Unicode extension subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __unicodeMappings = {
// property names and values must be in canonical case
"ca": {
"ethiopic-amete-alem": "ethioaa",
"islamicc": "islamic-civil",
},
"kb": {
"yes": "true",
},
"kc": {
"yes": "true",
},
"kh": {
"yes": "true",
},
"kk": {
"yes": "true",
},
"kn": {
"yes": "true",
},
"ks": {
"primary": "level1",
"tertiary": "level3",
},
"ms": {
"imperial": "uksystem",
},
"rg": {
"cn11": "cnbj",
"cn12": "cntj",
"cn13": "cnhe",
"cn14": "cnsx",
"cn15": "cnmn",
"cn21": "cnln",
"cn22": "cnjl",
"cn23": "cnhl",
"cn31": "cnsh",
"cn32": "cnjs",
"cn33": "cnzj",
"cn34": "cnah",
"cn35": "cnfj",
"cn36": "cnjx",
"cn37": "cnsd",
"cn41": "cnha",
"cn42": "cnhb",
"cn43": "cnhn",
"cn44": "cngd",
"cn45": "cngx",
"cn46": "cnhi",
"cn50": "cncq",
"cn51": "cnsc",
"cn52": "cngz",
"cn53": "cnyn",
"cn54": "cnxz",
"cn61": "cnsn",
"cn62": "cngs",
"cn63": "cnqh",
"cn64": "cnnx",
"cn65": "cnxj",
"cz10a": "cz110",
"cz10b": "cz111",
"cz10c": "cz112",
"cz10d": "cz113",
"cz10e": "cz114",
"cz10f": "cz115",
"cz611": "cz663",
"cz612": "cz632",
"cz613": "cz633",
"cz614": "cz634",
"cz615": "cz635",
"cz621": "cz641",
"cz622": "cz642",
"cz623": "cz643",
"cz624": "cz644",
"cz626": "cz646",
"cz627": "cz647",
"czjc": "cz31",
"czjm": "cz64",
"czka": "cz41",
"czkr": "cz52",
"czli": "cz51",
"czmo": "cz80",
"czol": "cz71",
"czpa": "cz53",
"czpl": "cz32",
"czpr": "cz10",
"czst": "cz20",
"czus": "cz42",
"czvy": "cz63",
"czzl": "cz72",
"fra": "frges",
"frb": "frnaq",
"frc": "frara",
"frd": "frbfc",
"fre": "frbre",
"frf": "frcvl",
"frg": "frges",
"frh": "frcor",
"fri": "frbfc",
"frj": "fridf",
"frk": "frocc",
"frl": "frnaq",
"frm": "frges",
"frn": "frocc",
"fro": "frhdf",
"frp": "frnor",
"frq": "frnor",
"frr": "frpdl",
"frs": "frhdf",
"frt": "frnaq",
"fru": "frpac",
"frv": "frara",
"laxn": "laxs",
"lud": "lucl",
"lug": "luec",
"lul": "luca",
"mrnkc": "mr13",
"no23": "no50",
"nzn": "nzauk",
"nzs": "nzcan",
"omba": "ombj",
"omsh": "omsj",
"plds": "pl02",
"plkp": "pl04",
"pllb": "pl08",
"plld": "pl10",
"pllu": "pl06",
"plma": "pl12",
"plmz": "pl14",
"plop": "pl16",
"plpd": "pl20",
"plpk": "pl18",
"plpm": "pl22",
"plsk": "pl26",
"plsl": "pl24",
"plwn": "pl28",
"plwp": "pl30",
"plzp": "pl32",
"tteto": "tttob",
"ttrcm": "ttmrc",
"ttwto": "tttob",
"twkhq": "twkhh",
"twtnq": "twtnn",
"twtpq": "twnwt",
"twtxq": "twtxg",
},
"sd": {
"cn11": "cnbj",
"cn12": "cntj",
"cn13": "cnhe",
"cn14": "cnsx",
"cn15": "cnmn",
"cn21": "cnln",
"cn22": "cnjl",
"cn23": "cnhl",
"cn31": "cnsh",
"cn32": "cnjs",
"cn33": "cnzj",
"cn34": "cnah",
"cn35": "cnfj",
"cn36": "cnjx",
"cn37": "cnsd",
"cn41": "cnha",
"cn42": "cnhb",
"cn43": "cnhn",
"cn44": "cngd",
"cn45": "cngx",
"cn46": "cnhi",
"cn50": "cncq",
"cn51": "cnsc",
"cn52": "cngz",
"cn53": "cnyn",
"cn54": "cnxz",
"cn61": "cnsn",
"cn62": "cngs",
"cn63": "cnqh",
"cn64": "cnnx",
"cn65": "cnxj",
"cz10a": "cz110",
"cz10b": "cz111",
"cz10c": "cz112",
"cz10d": "cz113",
"cz10e": "cz114",
"cz10f": "cz115",
"cz611": "cz663",
"cz612": "cz632",
"cz613": "cz633",
"cz614": "cz634",
"cz615": "cz635",
"cz621": "cz641",
"cz622": "cz642",
"cz623": "cz643",
"cz624": "cz644",
"cz626": "cz646",
"cz627": "cz647",
"czjc": "cz31",
"czjm": "cz64",
"czka": "cz41",
"czkr": "cz52",
"czli": "cz51",
"czmo": "cz80",
"czol": "cz71",
"czpa": "cz53",
"czpl": "cz32",
"czpr": "cz10",
"czst": "cz20",
"czus": "cz42",
"czvy": "cz63",
"czzl": "cz72",
"fra": "frges",
"frb": "frnaq",
"frc": "frara",
"frd": "frbfc",
"fre": "frbre",
"frf": "frcvl",
"frg": "frges",
"frh": "frcor",
"fri": "frbfc",
"frj": "fridf",
"frk": "frocc",
"frl": "frnaq",
"frm": "frges",
"frn": "frocc",
"fro": "frhdf",
"frp": "frnor",
"frq": "frnor",
"frr": "frpdl",
"frs": "frhdf",
"frt": "frnaq",
"fru": "frpac",
"frv": "frara",
"laxn": "laxs",
"lud": "lucl",
"lug": "luec",
"lul": "luca",
"mrnkc": "mr13",
"no23": "no50",
"nzn": "nzauk",
"nzs": "nzcan",
"omba": "ombj",
"omsh": "omsj",
"plds": "pl02",
"plkp": "pl04",
"pllb": "pl08",
"plld": "pl10",
"pllu": "pl06",
"plma": "pl12",
"plmz": "pl14",
"plop": "pl16",
"plpd": "pl20",
"plpk": "pl18",
"plpm": "pl22",
"plsk": "pl26",
"plsl": "pl24",
"plwn": "pl28",
"plwp": "pl30",
"plzp": "pl32",
"tteto": "tttob",
"ttrcm": "ttmrc",
"ttwto": "tttob",
"twkhq": "twkhh",
"twtnq": "twtnn",
"twtpq": "twnwt",
"twtxq": "twtxg",
},
"tz": {
"aqams": "nzakl",
"cnckg": "cnsha",
"cnhrb": "cnsha",
"cnkhg": "cnurc",
"cuba": "cuhav",
"egypt": "egcai",
"eire": "iedub",
"est": "utcw05",
"gmt0": "gmt",
"hongkong": "hkhkg",
"hst": "utcw10",
"iceland": "isrey",
"iran": "irthr",
"israel": "jeruslm",
"jamaica": "jmkin",
"japan": "jptyo",
"libya": "lytip",
"mst": "utcw07",
"navajo": "usden",
"poland": "plwaw",
"portugal": "ptlis",
"prc": "cnsha",
"roc": "twtpe",
"rok": "krsel",
"turkey": "trist",
"uct": "utc",
"usnavajo": "usden",
"zulu": "utc",
},
};
/**
* Mappings from Unicode extension subtags to preferred values.
*
* Spec: http://unicode.org/reports/tr35/#Identifiers
* Version: CLDR, version 36.1
*/
var __transformMappings = {
// property names and values must be in canonical case
"d0": {
"name": "charname",
},
"m0": {
"names": "prprname",
},
};
/**
* Canonicalizes the given well-formed BCP 47 language tag, including regularized case of subtags.
*
* Spec: ECMAScript Internationalization API Specification, draft, 6.2.3.
* Spec: RFC 5646, section 4.5.
*/
function canonicalizeLanguageTag(locale) {
// start with lower case for easier processing, and because most subtags will need to be lower case anyway
locale = locale.toLowerCase();
// handle mappings for complete tags
if (__tagMappings.hasOwnProperty(locale)) {
return __tagMappings[locale];
}
var subtags = locale.split("-");
var i = 0;
// handle standard part: all subtags before first variant or singleton subtag
var language;
var script;
var region;
while (i < subtags.length) {
var subtag = subtags[i];
if (i === 0) {
language = subtag;
} else if (subtag.length === 2 || subtag.length === 3) {
region = subtag.toUpperCase();
} else if (subtag.length === 4 && !("0" <= subtag[0] && subtag[0] <= "9")) {
script = subtag[0].toUpperCase() + subtag.substring(1).toLowerCase();
} else {
break;
}
i++;
}
if (__languageMappings.hasOwnProperty(language)) {
language = __languageMappings[language];
} else if (__complexLanguageMappings.hasOwnProperty(language)) {
var mapping = __complexLanguageMappings[language];
language = mapping.language;
if (script === undefined && mapping.hasOwnProperty("script")) {
script = mapping.script;
}
if (region === undefined && mapping.hasOwnProperty("region")) {
region = mapping.region;
}
}
if (region !== undefined) {
if (__regionMappings.hasOwnProperty(region)) {
region = __regionMappings[region];
} else if (__complexRegionMappings.hasOwnProperty(region)) {
var mapping = __complexRegionMappings[region];
var mappingKey = language;
if (script !== undefined) {
mappingKey += "-" + script;
}
if (mapping.hasOwnProperty(mappingKey)) {
region = mapping[mappingKey];
} else {
region = mapping.default;
}
}
}
// handle variants
var variants = [];
while (i < subtags.length && subtags[i].length > 1) {
var variant = subtags[i];
if (__variantMappings.hasOwnProperty(variant)) {
var mapping = __variantMappings[variant];
switch (mapping.type) {
case "language":
language = mapping.replacement;
break;
case "region":
region = mapping.replacement;
break;
case "variant":
variants.push(mapping.replacement);
break;
default:
throw new Error("illegal variant mapping type");
}
} else {
variants.push(variant);
}
i += 1;
}
variants.sort();
// handle extensions
var extensions = [];
while (i < subtags.length && subtags[i] !== "x") {
var extensionStart = i;
i++;
while (i < subtags.length && subtags[i].length > 1) {
i++;
}
var extension;
var extensionKey = subtags[extensionStart];
if (extensionKey === "u") {
var j = extensionStart + 1;
// skip over leading attributes
while (j < i && subtags[j].length > 2) {
j++;
}
extension = subtags.slice(extensionStart, j).join("-");
while (j < i) {
var keyStart = j;
j++;
while (j < i && subtags[j].length > 2) {
j++;
}
var key = subtags[keyStart];
var value = subtags.slice(keyStart + 1, j).join("-");
if (__unicodeMappings.hasOwnProperty(key)) {
var mapping = __unicodeMappings[key];
if (mapping.hasOwnProperty(value)) {
value = mapping[value];
}
}
extension += "-" + key;
if (value !== "" && value !== "true") {
extension += "-" + value;
}
}
} else if (extensionKey === "t") {
var j = extensionStart + 1;
while (j < i && !transformKeyRE.test(subtags[j])) {
j++;
}
extension = "t";
var transformLanguage = subtags.slice(extensionStart + 1, j).join("-");
if (transformLanguage !== "") {
extension += "-" + canonicalizeLanguageTag(transformLanguage).toLowerCase();
}
while (j < i) {
var keyStart = j;
j++;
while (j < i && subtags[j].length > 2) {
j++;
}
var key = subtags[keyStart];
var value = subtags.slice(keyStart + 1, j).join("-");
if (__transformMappings.hasOwnProperty(key)) {
var mapping = __transformMappings[key];
if (mapping.hasOwnProperty(value)) {
value = mapping[value];
}
}
extension += "-" + key + "-" + value;
}
} else {
extension = subtags.slice(extensionStart, i).join("-");
}
extensions.push(extension);
}
extensions.sort();
// handle private use
var privateUse;
if (i < subtags.length) {
privateUse = subtags.slice(i).join("-");
}
// put everything back together
var canonical = language;
if (script !== undefined) {
canonical += "-" + script;
}
if (region !== undefined) {
canonical += "-" + region;
}
if (variants.length > 0) {
canonical += "-" + variants.join("-");
}
if (extensions.length > 0) {
canonical += "-" + extensions.join("-");
}
if (privateUse !== undefined) {
if (canonical.length > 0) {
canonical += "-" + privateUse;
} else {
canonical = privateUse;
}
}
return canonical;
}
return typeof locale === "string" && isStructurallyValidLanguageTag(locale) &&
canonicalizeLanguageTag(locale) === locale;
}
/**
* Returns an array of error cases handled by CanonicalizeLocaleList().
*/
function getInvalidLocaleArguments() {
function CustomError() {}
var topLevelErrors = [
// fails ToObject
[null, TypeError],
// fails Get
[{ get length() { throw new CustomError(); } }, CustomError],
// fail ToLength
[{ length: Symbol.toPrimitive }, TypeError],
[{ length: { get [Symbol.toPrimitive]() { throw new CustomError(); } } }, CustomError],
[{ length: { [Symbol.toPrimitive]() { throw new CustomError(); } } }, CustomError],
[{ length: { get valueOf() { throw new CustomError(); } } }, CustomError],
[{ length: { valueOf() { throw new CustomError(); } } }, CustomError],
[{ length: { get toString() { throw new CustomError(); } } }, CustomError],
[{ length: { toString() { throw new CustomError(); } } }, CustomError],
// fail type check
[[undefined], TypeError],
[[null], TypeError],
[[true], TypeError],
[[Symbol.toPrimitive], TypeError],
[[1], TypeError],
[[0.1], TypeError],
[[NaN], TypeError],
];
var invalidLanguageTags = [
"", // empty tag
"i", // singleton alone
"x", // private use without subtag
"u", // extension singleton in first place
"419", // region code in first place
"u-nu-latn-cu-bob", // extension sequence without language
"hans-cmn-cn", // "hans" could theoretically be a 4-letter language code,
// but those can't be followed by extlang codes.
"abcdefghi", // overlong language
"cmn-hans-cn-u-u", // duplicate singleton
"cmn-hans-cn-t-u-ca-u", // duplicate singleton
"de-gregory-gregory", // duplicate variant
"*", // language range
"de-*", // language range
"中文", // non-ASCII letters
"en-ß", // non-ASCII letters
"ıd" // non-ASCII letters
];
return topLevelErrors.concat(
invalidLanguageTags.map(tag => [tag, RangeError]),
invalidLanguageTags.map(tag => [[tag], RangeError]),
invalidLanguageTags.map(tag => [["en", tag], RangeError]),
)
}
/**
* Tests whether the named options property is correctly handled by the given constructor.
* @param {object} Constructor the constructor to test.
* @param {string} property the name of the options property to test.
* @param {string} type the type that values of the property are expected to have
* @param {Array} [values] an array of allowed values for the property. Not needed for boolean.
* @param {any} fallback the fallback value that the property assumes if not provided.
* @param {object} testOptions additional options:
* @param {boolean} isOptional whether support for this property is optional for implementations.
* @param {boolean} noReturn whether the resulting value of the property is not returned.
* @param {boolean} isILD whether the resulting value of the property is implementation and locale dependent.
* @param {object} extra additional option to pass along, properties are value -> {option: value}.
*/
function testOption(Constructor, property, type, values, fallback, testOptions) {
var isOptional = testOptions !== undefined && testOptions.isOptional === true;
var noReturn = testOptions !== undefined && testOptions.noReturn === true;
var isILD = testOptions !== undefined && testOptions.isILD === true;
function addExtraOptions(options, value, testOptions) {
if (testOptions !== undefined && testOptions.extra !== undefined) {
var extra;
if (value !== undefined && testOptions.extra[value] !== undefined) {
extra = testOptions.extra[value];
} else if (testOptions.extra.any !== undefined) {
extra = testOptions.extra.any;
}
if (extra !== undefined) {
Object.getOwnPropertyNames(extra).forEach(function (prop) {
options[prop] = extra[prop];
});
}
}
}
var testValues, options, obj, expected, actual, error;
// test that the specified values are accepted. Also add values that convert to specified values.
if (type === "boolean") {
if (values === undefined) {
values = [true, false];
}
testValues = values.slice(0);
testValues.push(888);
testValues.push(0);
} else if (type === "string") {
testValues = values.slice(0);
testValues.push({toString: function () { return values[0]; }});
}
testValues.forEach(function (value) {
options = {};
options[property] = value;
addExtraOptions(options, value, testOptions);
obj = new Constructor(undefined, options);
if (noReturn) {
if (obj.resolvedOptions().hasOwnProperty(property)) {
throw new Test262Error("Option property " + property + " is returned, but shouldn't be.");
}
} else {
actual = obj.resolvedOptions()[property];
if (isILD) {
if (actual !== undefined && values.indexOf(actual) === -1) {
throw new Test262Error("Invalid value " + actual + " returned for property " + property + ".");
}
} else {
if (type === "boolean") {
expected = Boolean(value);
} else if (type === "string") {
expected = String(value);
}
if (actual !== expected && !(isOptional && actual === undefined)) {
throw new Test262Error("Option value " + value + " for property " + property +
" was not accepted; got " + actual + " instead.");
}
}
}
});
// test that invalid values are rejected
if (type === "string") {
var invalidValues = ["invalidValue", -1, null];
// assume that we won't have values in caseless scripts
if (values[0].toUpperCase() !== values[0]) {
invalidValues.push(values[0].toUpperCase());
} else {
invalidValues.push(values[0].toLowerCase());
}
invalidValues.forEach(function (value) {
options = {};
options[property] = value;
addExtraOptions(options, value, testOptions);
error = undefined;
try {
obj = new Constructor(undefined, options);
} catch (e) {
error = e;
}
if (error === undefined) {
throw new Test262Error("Invalid option value " + value + " for property " + property + " was not rejected.");
} else if (error.name !== "RangeError") {
throw new Test262Error("Invalid option value " + value + " for property " + property + " was rejected with wrong error " + error.name + ".");
}
});
}
// test that fallback value or another valid value is used if no options value is provided
if (!noReturn) {
options = {};
addExtraOptions(options, undefined, testOptions);
obj = new Constructor(undefined, options);
actual = obj.resolvedOptions()[property];
if (!(isOptional && actual === undefined)) {
if (fallback !== undefined) {
if (actual !== fallback) {
throw new Test262Error("Option fallback value " + fallback + " for property " + property +
" was not used; got " + actual + " instead.");
}
} else {
if (values.indexOf(actual) === -1 && !(isILD && actual === undefined)) {
throw new Test262Error("Invalid value " + actual + " returned for property " + property + ".");
}
}
}
}
}
/**
* Properties of the RegExp constructor that may be affected by use of regular
* expressions, and the default values of these properties. Properties are from
* https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Deprecated_and_obsolete_features#RegExp_Properties
*/
var regExpProperties = ["$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9",
"$_", "$*", "$&", "$+", "$`", "$'",
"input", "lastMatch", "lastParen", "leftContext", "rightContext"
];
var regExpPropertiesDefaultValues = (function () {
var values = Object.create(null);
(/(?:)/).test("");
regExpProperties.forEach(function (property) {
values[property] = RegExp[property];
});
return values;
}());
/**
* Tests that executing the provided function (which may use regular expressions
* in its implementation) does not create or modify unwanted properties on the
* RegExp constructor.
*/
function testForUnwantedRegExpChanges(testFunc) {
(/(?:)/).test("");
testFunc();
regExpProperties.forEach(function (property) {
if (RegExp[property] !== regExpPropertiesDefaultValues[property]) {
throw new Test262Error("RegExp has unexpected property " + property + " with value " +
RegExp[property] + ".");
}
});
}
/**
* Returns an array of all known calendars.
*/
function allCalendars() {
// source: CLDR file common/bcp47/number.xml; version CLDR 39.
// https://github.com/unicode-org/cldr/blob/master/common/bcp47/calendar.xml
return [
"buddhist",
"chinese",
"coptic",
"dangi",
"ethioaa",
"ethiopic",
"gregory",
"hebrew",
"indian",
"islamic",
"islamic-umalqura",
"islamic-tbla",
"islamic-civil",
"islamic-rgsa",
"iso8601",
"japanese",
"persian",
"roc",
];
}
/**
* Returns an array of all known collations.
*/
function allCollations() {
// source: CLDR file common/bcp47/collation.xml; version CLDR 39.
// https://github.com/unicode-org/cldr/blob/master/common/bcp47/collation.xml
return [
"big5han",
"compat",
"dict",
"direct",
"ducet",
"emoji",
"eor",
"gb2312",
"phonebk",
"phonetic",
"pinyin",
"reformed",
"search",
"searchjl",
"standard",
"stroke",
"trad",
"unihan",
"zhuyin",
];
}
/**
* Returns an array of all known numbering systems.
*/
function allNumberingSystems() {
// source: CLDR file common/bcp47/number.xml; version CLDR 39.
// https://github.com/unicode-org/cldr/blob/master/common/bcp47/number.xml
return [
"adlm",
"ahom",
"arab",
"arabext",
"armn",
"armnlow",
"bali",
"beng",
"bhks",
"brah",
"cakm",
"cham",
"cyrl",
"deva",
"diak",
"ethi",
"finance",
"fullwide",
"geor",
"gong",
"gonm",
"grek",
"greklow",
"gujr",
"guru",
"hanidays",
"hanidec",
"hans",
"hansfin",
"hant",
"hantfin",
"hebr",
"hmng",
"hmnp",
"java",
"jpan",
"jpanfin",
"jpanyear",
"kali",
"khmr",
"knda",
"lana",
"lanatham",
"laoo",
"latn",
"lepc",
"limb",
"mathbold",
"mathdbl",
"mathmono",
"mathsanb",
"mathsans",
"mlym",
"modi",
"mong",
"mroo",
"mtei",
"mymr",
"mymrshan",
"mymrtlng",
"native",
"newa",
"nkoo",
"olck",
"orya",
"osma",
"rohg",
"roman",
"romanlow",
"saur",
"shrd",
"sind",
"sinh",
"sora",
"sund",
"takr",
"talu",
"taml",
"tamldec",
"telu",
"thai",
"tirh",
"tibt",
"traditio",
"vaii",
"wara",
"wcho",
];
}
/**
* Tests whether name is a valid BCP 47 numbering system name
* and not excluded from use in the ECMAScript Internationalization API.
* @param {string} name the name to be tested.
* @return {boolean} whether name is a valid BCP 47 numbering system name and
* allowed for use in the ECMAScript Internationalization API.
*/
function isValidNumberingSystem(name) {
var numberingSystems = allNumberingSystems();
var excluded = [
"finance",
"native",
"traditio"
];
return numberingSystems.indexOf(name) !== -1 && excluded.indexOf(name) === -1;
}
/**
* Provides the digits of numbering systems with simple digit mappings,
* as specified in 11.3.2.
*/
var numberingSystemDigits = {
adlm: "𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙",
ahom: "𑜰𑜱𑜲𑜳𑜴𑜵𑜶𑜷𑜸𑜹",
arab: "٠١٢٣٤٥٦٧٨٩",
arabext: "۰۱۲۳۴۵۶۷۸۹",
bali: "\u1B50\u1B51\u1B52\u1B53\u1B54\u1B55\u1B56\u1B57\u1B58\u1B59",
beng: "০১২৩৪৫৬৭৮৯",
bhks: "𑱐𑱑𑱒𑱓𑱔𑱕𑱖𑱗𑱘𑱙",
brah: "𑁦𑁧𑁨𑁩𑁪𑁫𑁬𑁭𑁮𑁯",
cakm: "𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿",
cham: "꩐꩑꩒꩓꩔꩕꩖꩗꩘꩙",
deva: "०१२३४५६७८९",
diak: "𑥐𑥑𑥒𑥓𑥔𑥕𑥖𑥗𑥘𑥙",
fullwide: "0123456789",
gong: "𑶠𑶡𑶢𑶣𑶤𑶥𑶦𑶧𑶨𑶩",
gonm: "𑵐𑵑𑵒𑵓𑵔𑵕𑵖𑵗𑵘𑵙",
gujr: "૦૧૨૩૪૫૬૭૮૯",
guru: "੦੧੨੩੪੫੬੭੮੯",
hanidec: "〇一二三四五六七八九",
hmng: "𖭐𖭑𖭒𖭓𖭔𖭕𖭖𖭗𖭘𖭙",
hmnp: "𞅀𞅁𞅂𞅃𞅄𞅅𞅆𞅇𞅈𞅉",
java: "꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙",
kali: "꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉",
khmr: "០១២៣៤៥៦៧៨៩",
knda: "೦೧೨೩೪೫೬೭೮೯",
lana: "᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉",
lanatham: "᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙",
laoo: "໐໑໒໓໔໕໖໗໘໙",
latn: "0123456789",
lepc: "᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉",
limb: "\u1946\u1947\u1948\u1949\u194A\u194B\u194C\u194D\u194E\u194F",
mathbold: "𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗",
mathdbl: "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡",
mathmono: "𝟶𝟷𝟸𝟹𝟺𝟻𝟼𝟽𝟾𝟿",
mathsanb: "𝟬𝟭𝟮𝟯𝟰𝟱𝟲𝟳𝟴𝟵",
mathsans: "𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫",
mlym: "൦൧൨൩൪൫൬൭൮൯",
modi: "𑙐𑙑𑙒𑙓𑙔𑙕𑙖𑙗𑙘𑙙",
mong: "᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙",
mroo: "𖩠𖩡𖩢𖩣𖩤𖩥𖩦𖩧𖩨𖩩",
mtei: "꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹",
mymr: "၀၁၂၃၄၅၆၇၈၉",
mymrshan: "႐႑႒႓႔႕႖႗႘႙",
mymrtlng: "꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹",
newa: "𑑐𑑑𑑒𑑓𑑔𑑕𑑖𑑗𑑘𑑙",
nkoo: "߀߁߂߃߄߅߆߇߈߉",
olck: "᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙",
orya: "୦୧୨୩୪୫୬୭୮୯",
osma: "𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩",
rohg: "𐴰𐴱𐴲𐴳𐴴𐴵𐴶𐴷𐴸𐴹",
saur: "꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙",
segment: "🯰🯱🯲🯳🯴🯵🯶🯷🯸🯹",
shrd: "𑇐𑇑𑇒𑇓𑇔𑇕𑇖𑇗𑇘𑇙",
sind: "𑋰𑋱𑋲𑋳𑋴𑋵𑋶𑋷𑋸𑋹",
sinh: "෦෧෨෩෪෫෬෭෮෯",
sora: "𑃰𑃱𑃲𑃳𑃴𑃵𑃶𑃷𑃸𑃹",
sund: "᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹",
takr: "𑛀𑛁𑛂𑛃𑛄𑛅𑛆𑛇𑛈𑛉",
talu: "᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙",
tamldec: "௦௧௨௩௪௫௬௭௮௯",
telu: "౦౧౨౩౪౫౬౭౮౯",
thai: "๐๑๒๓๔๕๖๗๘๙",
tibt: "༠༡༢༣༤༥༦༧༨༩",
tirh: "𑓐𑓑𑓒𑓓𑓔𑓕𑓖𑓗𑓘𑓙",
vaii: "꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩",
wara: "𑣠𑣡𑣢𑣣𑣤𑣥𑣦𑣧𑣨𑣩",
wcho: "𞋰𞋱𞋲𞋳𞋴𞋵𞋶𞋷𞋸𞋹",
};
/**
* Returns an array of all simple, sanctioned unit identifiers.
*/
function allSimpleSanctionedUnits() {
// https://tc39.es/ecma402/#table-sanctioned-simple-unit-identifiers
return [
"acre",
"bit",
"byte",
"celsius",
"centimeter",
"day",
"degree",
"fahrenheit",
"fluid-ounce",
"foot",
"gallon",
"gigabit",
"gigabyte",
"gram",
"hectare",
"hour",
"inch",
"kilobit",
"kilobyte",
"kilogram",
"kilometer",
"liter",
"megabit",
"megabyte",
"meter",
"mile",
"mile-scandinavian",
"milliliter",
"millimeter",
"millisecond",
"minute",
"month",
"ounce",
"percent",
"petabyte",
"pound",
"second",
"stone",
"terabit",
"terabyte",
"week",
"yard",
"year",
];
}
/**
* Tests that number formatting is handled correctly. The function checks that the
* digit sequences in formatted output are as specified, converted to the
* selected numbering system, and embedded in consistent localized patterns.
* @param {Array} locales the locales to be tested.
* @param {Array} numberingSystems the numbering systems to be tested.
* @param {Object} options the options to pass to Intl.NumberFormat. Options
* must include {useGrouping: false}, and must cause 1.1 to be formatted
* pre- and post-decimal digits.
* @param {Object} testData maps input data (in ES5 9.3.1 format) to expected output strings
* in unlocalized format with Western digits.
*/
function testNumberFormat(locales, numberingSystems, options, testData) {
locales.forEach(function (locale) {
numberingSystems.forEach(function (numbering) {
var digits = numberingSystemDigits[numbering];
var format = new Intl.NumberFormat([locale + "-u-nu-" + numbering], options);
function getPatternParts(positive) {
var n = positive ? 1.1 : -1.1;
var formatted = format.format(n);
var oneoneRE = "([^" + digits + "]*)[" + digits + "]+([^" + digits + "]+)[" + digits + "]+([^" + digits + "]*)";
var match = formatted.match(new RegExp(oneoneRE));
if (match === null) {
throw new Test262Error("Unexpected formatted " + n + " for " +
format.resolvedOptions().locale + " and options " +
JSON.stringify(options) + ": " + formatted);
}
return match;
}
function toNumbering(raw) {
return raw.replace(/[0-9]/g, function (digit) {
return digits[digit.charCodeAt(0) - "0".charCodeAt(0)];
});
}
function buildExpected(raw, patternParts) {
var period = raw.indexOf(".");
if (period === -1) {
return patternParts[1] + toNumbering(raw) + patternParts[3];
} else {
return patternParts[1] +
toNumbering(raw.substring(0, period)) +
patternParts[2] +
toNumbering(raw.substring(period + 1)) +
patternParts[3];
}
}
if (format.resolvedOptions().numberingSystem === numbering) {
// figure out prefixes, infixes, suffixes for positive and negative values
var posPatternParts = getPatternParts(true);
var negPatternParts = getPatternParts(false);
Object.getOwnPropertyNames(testData).forEach(function (input) {
var rawExpected = testData[input];
var patternParts;
if (rawExpected[0] === "-") {
patternParts = negPatternParts;
rawExpected = rawExpected.substring(1);
} else {
patternParts = posPatternParts;
}
var expected = buildExpected(rawExpected, patternParts);
var actual = format.format(input);
if (actual !== expected) {
throw new Test262Error("Formatted value for " + input + ", " +
format.resolvedOptions().locale + " and options " +
JSON.stringify(options) + " is " + actual + "; expected " + expected + ".");
}
});
}
});
});
}
/**
* Return the components of date-time formats.
* @return {Array} an array with all date-time components.
*/
function getDateTimeComponents() {
return ["weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"];
}
/**
* Return the valid values for the given date-time component, as specified
* by the table in section 12.1.1.
* @param {string} component a date-time component.
* @return {Array} an array with the valid values for the component.
*/
function getDateTimeComponentValues(component) {
var components = {
weekday: ["narrow", "short", "long"],
era: ["narrow", "short", "long"],
year: ["2-digit", "numeric"],
month: ["2-digit", "numeric", "narrow", "short", "long"],
day: ["2-digit", "numeric"],
hour: ["2-digit", "numeric"],
minute: ["2-digit", "numeric"],
second: ["2-digit", "numeric"],
timeZoneName: ["short", "long"]
};
var result = components[component];
if (result === undefined) {
throw new Test262Error("Internal error: No values defined for date-time component " + component + ".");
}
return result;
}
/**
* @description Tests whether timeZone is a String value representing a
* structurally valid and canonicalized time zone name, as defined in
* sections 6.4.1 and 6.4.2 of the ECMAScript Internationalization API
* Specification.
* @param {String} timeZone the string to be tested.
* @result {Boolean} whether the test succeeded.
*/
function isCanonicalizedStructurallyValidTimeZoneName(timeZone) {
/**
* Regular expression defining IANA Time Zone names.
*
* Spec: IANA Time Zone Database, Theory file
*/
var fileNameComponent = "(?:[A-Za-z_]|\\.(?!\\.?(?:/|$)))[A-Za-z.\\-_]{0,13}";
var fileName = fileNameComponent + "(?:/" + fileNameComponent + ")*";
var etcName = "(?:Etc/)?GMT[+-]\\d{1,2}";
var systemVName = "SystemV/[A-Z]{3}\\d{1,2}(?:[A-Z]{3})?";
var legacyName = etcName + "|" + systemVName + "|CST6CDT|EST5EDT|MST7MDT|PST8PDT|NZ";
var zoneNamePattern = new RegExp("^(?:" + fileName + "|" + legacyName + ")$");
if (typeof timeZone !== "string") {
return false;
}
// 6.4.2 CanonicalizeTimeZoneName (timeZone), step 3
if (timeZone === "UTC") {
return true;
}
// 6.4.2 CanonicalizeTimeZoneName (timeZone), step 3
if (timeZone === "Etc/UTC" || timeZone === "Etc/GMT") {
return false;
}
return zoneNamePattern.test(timeZone);
}