From c052050403ce3697790f9983b4756b354349f982 Mon Sep 17 00:00:00 2001 From: Long Ho Date: Mon, 20 Apr 2020 00:55:55 -0400 Subject: [PATCH] feat(intl-messageformat-parser): Fix number skeleton parser Initially we didn't handle `.###` case. BREAKING CHANGE: Change precision wildcard token from `+` to `*` to conform with ICU67+ --- .../intl-messageformat-parser/src/skeleton.ts | 34 +++++++++++-------- .../number_skeleton.test.ts.snap | 27 +++++++++++++-- .../test/number_skeleton.test.ts | 7 ++-- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/packages/intl-messageformat-parser/src/skeleton.ts b/packages/intl-messageformat-parser/src/skeleton.ts index c0dbb2c52..88ec4d2b7 100644 --- a/packages/intl-messageformat-parser/src/skeleton.ts +++ b/packages/intl-messageformat-parser/src/skeleton.ts @@ -150,7 +150,7 @@ function icuUnitToEcma(unit: string): UnifiedNumberFormatOptions['unit'] { return unit.replace(/^(.*?)-/, '') as UnifiedNumberFormatOptions['unit']; } -const FRACTION_PRECISION_REGEX = /^\.(?:(0+)(\+|#+)?)?$/g; +const FRACTION_PRECISION_REGEX = /^\.(?:(0+)(\*)?|(#+)|(0+)(#+))$/g; const SIGNIFICANT_PRECISION_REGEX = /^(@+)?(\+|#+)?$/g; function parseSignificantPrecision(str: string): UnifiedNumberFormatOptions { @@ -248,6 +248,7 @@ export function convertNumberSkeletonToNumberFormatOptions( result.useGrouping = false; continue; case 'precision-integer': + case '.': result.maximumFractionDigits = 0; continue; case 'measure-unit': @@ -304,6 +305,7 @@ export function convertNumberSkeletonToNumberFormatOptions( } // Precision // https://github.com/unicode-org/icu/blob/master/docs/userguide/format_parse/numbers/skeletons.md#fraction-precision + // precision-integer case if (FRACTION_PRECISION_REGEX.test(token.stem)) { if (token.options.length > 1) { throw new RangeError( @@ -313,28 +315,30 @@ export function convertNumberSkeletonToNumberFormatOptions( token.stem.replace(FRACTION_PRECISION_REGEX, function( match: string, g1: string, - g2: string | number + g2: string | number, + g3: string, + g4: string, + g5: string ) { - // precision-integer case - if (match === '.') { - result.maximumFractionDigits = 0; - } - // .000+ case - else if (g2 === '+') { - result.minimumFractionDigits = g2.length; + // .000* case (before ICU67 it was .000+) + if (g2 === '*') { + result.minimumFractionDigits = g1.length; } // .### case - else if (g1[0] === '#') { - result.maximumFractionDigits = g1.length; + else if (g3 && g3[0] === '#') { + result.maximumFractionDigits = g3.length; } - // .00## or .000 case - else { + // .00## case + else if (g4 && g5) { + result.minimumFractionDigits = g4.length; + result.maximumFractionDigits = g4.length + g5.length; + } else { result.minimumFractionDigits = g1.length; - result.maximumFractionDigits = - g1.length + (typeof g2 === 'string' ? g2.length : 0); + result.maximumFractionDigits = g1.length; } return ''; }); + if (token.options.length) { result = {...result, ...parseSignificantPrecision(token.options[0])}; } diff --git a/packages/intl-messageformat-parser/test/__snapshots__/number_skeleton.test.ts.snap b/packages/intl-messageformat-parser/test/__snapshots__/number_skeleton.test.ts.snap index 35514b45c..7db580eb4 100644 --- a/packages/intl-messageformat-parser/test/__snapshots__/number_skeleton.test.ts.snap +++ b/packages/intl-messageformat-parser/test/__snapshots__/number_skeleton.test.ts.snap @@ -22,7 +22,7 @@ Object { } `; -exports[`[convertNumberSkeletonToNumberFormatOptions] case: "currency/GBP .0+/@@@" 1`] = ` +exports[`[convertNumberSkeletonToNumberFormatOptions] case: "currency/GBP .0*/@@@" 1`] = ` Object { "currency": "GBP", "maximumSignificantDigits": 3, @@ -99,6 +99,21 @@ Object { } `; +exports[`[convertNumberSkeletonToNumberFormatOptions] case: "percent .##" 1`] = ` +Object { + "maximumFractionDigits": 2, + "style": "percent", +} +`; + +exports[`[convertNumberSkeletonToNumberFormatOptions] case: "percent .0###" 1`] = ` +Object { + "maximumFractionDigits": 4, + "minimumFractionDigits": 1, + "style": "percent", +} +`; + exports[`[convertNumberSkeletonToNumberFormatOptions] case: "percent .00/@##" 1`] = ` Object { "maximumFractionDigits": 2, @@ -119,11 +134,17 @@ Object { } `; -exports[`[convertNumberSkeletonToNumberFormatOptions] case: "percent .00/@@@@+" 1`] = ` +exports[`[convertNumberSkeletonToNumberFormatOptions] case: "percent .00/@@@@*" 1`] = ` Object { "maximumFractionDigits": 2, "minimumFractionDigits": 2, - "minimumSignificantDigits": 4, + "style": "percent", +} +`; + +exports[`[convertNumberSkeletonToNumberFormatOptions] case: "percent .000*" 1`] = ` +Object { + "minimumFractionDigits": 3, "style": "percent", } `; diff --git a/packages/intl-messageformat-parser/test/number_skeleton.test.ts b/packages/intl-messageformat-parser/test/number_skeleton.test.ts index 9e951bfdb..85d5d0aac 100644 --- a/packages/intl-messageformat-parser/test/number_skeleton.test.ts +++ b/packages/intl-messageformat-parser/test/number_skeleton.test.ts @@ -14,11 +14,14 @@ test.each([ }); test.each([ + 'percent .##', + 'percent .000*', + 'percent .0###', 'percent .00/@##', 'percent .00/@@@', - 'percent .00/@@@@+', + 'percent .00/@@@@*', 'currency/CAD .', - 'currency/GBP .0+/@@@', + 'currency/GBP .0*/@@@', 'currency/GBP .00##/@@@', 'currency/GBP .00##/@@@ unit-width-full-name', 'measure-unit/length-meter .00##/@@@',