From c3ac5445e7c23eaf21e00f8af3055661d9ace594 Mon Sep 17 00:00:00 2001 From: Linjie Ding Date: Sun, 26 Apr 2020 08:42:29 -0700 Subject: [PATCH] fix(@formatjs/intl-unified-numberformat): validate numbering system (#676) --- .vscode/settings.json | 5 ++- .vscode/tasks.json | 16 ++++++++ .../src/extract-numbers.ts | 9 ++++- .../formatjs-extract-cldr-data/src/index.ts | 5 ++- .../intl-unified-numberformat/scripts/cldr.ts | 7 ++++ .../intl-unified-numberformat/src/core.ts | 40 ++++++++++++++----- .../src/numbering-systems.json | 1 + .../intl-unified-numberformat/tests/runner.ts | 2 +- .../intl-unified-numberformat/tsconfig.json | 2 - tsconfig.json | 2 + 10 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 packages/intl-unified-numberformat/src/numbering-systems.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 3a0fe60cc..7c9976283 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,5 +22,8 @@ "url": "http://json.schemastore.org/lerna" } ], - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.tsdk": "node_modules/typescript/lib", + "npm.packageManager": "yarn", + "prettier.packageManager": "yarn", + "eslint.packageManager": "yarn" } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..fc53d5fc7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "dev:cjs", + "problemMatcher": ["$tsc-watch"], + "label": "yarn: dev:cjs", + "detail": "tsc -b packages/* --watch", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/packages/formatjs-extract-cldr-data/src/extract-numbers.ts b/packages/formatjs-extract-cldr-data/src/extract-numbers.ts index 70d6b7f0d..48632b737 100644 --- a/packages/formatjs-extract-cldr-data/src/extract-numbers.ts +++ b/packages/formatjs-extract-cldr-data/src/extract-numbers.ts @@ -3,8 +3,8 @@ * Copyrights licensed under the New BSD License. * See the accompanying LICENSE file for terms. */ -'use strict'; import * as NumbersData from 'cldr-numbers-full/main/ar/numbers.json'; +import * as numberingSystems from 'cldr-core/supplemental/numberingSystems.json'; import {Locale} from './types'; import generateFieldExtractorFn, { collapseSingleValuePluralRule, @@ -148,6 +148,13 @@ export function generateDataForLocales( }, {}); } +export function extractNumberingSystemNames() { + // Export an object instead of array to be more compatible with rollup. + return { + names: Object.keys(numberingSystems.supplemental.numberingSystems), + }; +} + export default generateFieldExtractorFn( loadNumbers, hasNumbers, diff --git a/packages/formatjs-extract-cldr-data/src/index.ts b/packages/formatjs-extract-cldr-data/src/index.ts index 03d95becb..2e6795498 100644 --- a/packages/formatjs-extract-cldr-data/src/index.ts +++ b/packages/formatjs-extract-cldr-data/src/index.ts @@ -49,5 +49,8 @@ export { generateDataForLocales as generateCurrencyDataForLocales, } from './extract-currencies'; export {generateDataForLocales as generateUnitDataForLocales} from './extract-units'; -export {generateDataForLocales as generateNumberDataForLocales} from './extract-numbers'; +export { + extractNumberingSystemNames, + generateDataForLocales as generateNumberDataForLocales, +} from './extract-numbers'; export {getAllLocales as getAllDisplayNamesLocales} from './extract-displaynames'; diff --git a/packages/intl-unified-numberformat/scripts/cldr.ts b/packages/intl-unified-numberformat/scripts/cldr.ts index 143a6ba35..509478a43 100644 --- a/packages/intl-unified-numberformat/scripts/cldr.ts +++ b/packages/intl-unified-numberformat/scripts/cldr.ts @@ -4,6 +4,7 @@ import { generateNumberDataForLocales, locales, extractCurrencyDigits, + extractNumberingSystemNames, } from 'formatjs-extract-cldr-data'; import { SANCTIONED_UNITS, @@ -146,6 +147,12 @@ outputJSONSync( extractCurrencyDigits() ); +// Output numbering systems file +outputJSONSync( + resolve(__dirname, '../src/numbering-systems.json'), + extractNumberingSystemNames() +); + // For test262 // Only a subset of locales outputFileSync( diff --git a/packages/intl-unified-numberformat/src/core.ts b/packages/intl-unified-numberformat/src/core.ts index d2906cd60..c48598c6d 100644 --- a/packages/intl-unified-numberformat/src/core.ts +++ b/packages/intl-unified-numberformat/src/core.ts @@ -47,6 +47,14 @@ import { import {extractILD, Patterns} from './data'; import * as currencyDigitsData from './currency-digits.json'; import * as ILND from './ilnd-numbers.json'; +import {names as numberingSystemNames} from './numbering-systems.json'; + +const VALID_NUMBERING_SYSTEM_NAMES: Record = Object.create( + null +); +for (const nu of numberingSystemNames) { + VALID_NUMBERING_SYSTEM_NAMES[nu] = true; +} const RESOLVED_OPTIONS_KEYS = [ 'locale', @@ -140,6 +148,7 @@ export type UnifiedNumberFormatOptions = Intl.NumberFormatOptions & signDisplay?: UnifiedNumberFormatOptionsSignDisplay; unit?: Unit; unitDisplay?: UnifiedNumberFormatOptionsUnitDisplay; + numberingSystem?: string; }; export type ResolvedUnifiedNumberFormatOptions = Intl.ResolvedNumberFormatOptions & @@ -203,7 +212,8 @@ function initializeNumberFormat( opts?: UnifiedNumberFormatOptions ) { const requestedLocales = getCanonicalLocales(locales); - const options = opts === undefined ? Object.create(null) : toObject(opts); + const options: UnifiedNumberFormatOptions = + opts === undefined ? Object.create(null) : toObject(opts); const opt: any = Object.create(null); const matcher = getOption( options, @@ -213,6 +223,24 @@ function initializeNumberFormat( 'best fit' ); opt.localeMatcher = matcher; + + const numberingSystem = getOption( + options, + 'numberingSystem', + 'string', + undefined, + undefined + ); + if ( + numberingSystem !== undefined && + !VALID_NUMBERING_SYSTEM_NAMES[numberingSystem] + ) { + // 8.a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, + // throw a RangeError exception. + throw RangeError(`Invalid numberingSystems: ${numberingSystem}`); + } + opt.nu = numberingSystem; + const {localeData} = UnifiedNumberFormat; const r = createResolveLocale(UnifiedNumberFormat.getDefaultLocale)( UnifiedNumberFormat.availableLocales, @@ -223,17 +251,11 @@ function initializeNumberFormat( localeData ); const ildData = localeData[removeUnicodeExtensionFromLocale(r.locale)]; - const numberingSystem = r.nu; setMultiInternalSlots(__INTERNAL_SLOT_MAP__, nf, { locale: r.locale, dataLocale: r.dataLocale, - numberingSystem, - ild: extractILD( - ildData.units, - ildData.currencies, - ildData.numbers, - numberingSystem - ), + numberingSystem: r.nu, + ild: extractILD(ildData.units, ildData.currencies, ildData.numbers, r.nu), }); // https://tc39.es/proposal-unified-intl-numberformat/section11/numberformat_proposed_out.html#sec-setnumberformatunitoptions diff --git a/packages/intl-unified-numberformat/src/numbering-systems.json b/packages/intl-unified-numberformat/src/numbering-systems.json new file mode 100644 index 000000000..a9ec02a49 --- /dev/null +++ b/packages/intl-unified-numberformat/src/numbering-systems.json @@ -0,0 +1 @@ +{"names":["adlm","ahom","arab","arabext","armn","armnlow","bali","beng","bhks","brah","cakm","cham","cyrl","deva","ethi","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","newa","nkoo","olck","orya","osma","rohg","roman","romanlow","saur","shrd","sind","sinh","sora","sund","takr","talu","taml","tamldec","telu","thai","tibt","tirh","vaii","wara","wcho"]} diff --git a/packages/intl-unified-numberformat/tests/runner.ts b/packages/intl-unified-numberformat/tests/runner.ts index 67fde6d4d..87a714103 100644 --- a/packages/intl-unified-numberformat/tests/runner.ts +++ b/packages/intl-unified-numberformat/tests/runner.ts @@ -1,7 +1,7 @@ import {spawnSync} from 'child_process'; import {resolve} from 'path'; import {cpus} from 'os'; -import chalk from 'chalk'; +import * as chalk from 'chalk'; if (process.version.startsWith('v13')) { console.log( diff --git a/packages/intl-unified-numberformat/tsconfig.json b/packages/intl-unified-numberformat/tsconfig.json index c1347bdb9..682bd90e7 100644 --- a/packages/intl-unified-numberformat/tsconfig.json +++ b/packages/intl-unified-numberformat/tsconfig.json @@ -4,8 +4,6 @@ "lib": ["dom", "es5", "esnext.intl", "es2017.intl", "es2018.intl"], "outDir": "dist", "rootDir": "src", - "allowSyntheticDefaultImports": true, - "noFallthroughCasesInSwitch": true, "types": [ "babel__core", "babel__generator", diff --git a/tsconfig.json b/tsconfig.json index edb81fb15..2466d7ecc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,8 @@ "noUnusedLocals": true, "noUnusedParameters": true, "preserveConstEnums": true, + "allowSyntheticDefaultImports": true, + "noFallthroughCasesInSwitch": true, "declarationMap": true, "sourceMap": true, "composite": true,