123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- import { parseTokens } from './pattern-parser/parse-tokens.js';
- import { parseNumberAsSkeleton } from './pattern-parser/number-as-skeleton.js';
- import { PatternError } from './errors.js';
- function handleAffix(affixTokens, res, currency, onError, isPrefix) {
- let inFmt = false;
- let str = '';
- for (const token of affixTokens) {
- switch (token.char) {
- case '%':
- res.unit = { style: token.style };
- if (isPrefix)
- inFmt = true;
- else
- str = '';
- break;
- case '¤':
- if (!currency) {
- const msg = `The ¤ pattern requires a currency`;
- onError(new PatternError('¤', msg));
- break;
- }
- res.unit = { style: 'currency', currency };
- switch (token.currency) {
- case 'iso-code':
- res.unitWidth = 'unit-width-iso-code';
- break;
- case 'full-name':
- res.unitWidth = 'unit-width-full-name';
- break;
- case 'narrow':
- res.unitWidth = 'unit-width-narrow';
- break;
- }
- if (isPrefix)
- inFmt = true;
- else
- str = '';
- break;
- case '*':
- // TODO
- break;
- case '+':
- if (!inFmt)
- str += '+';
- break;
- case "'":
- if (!inFmt)
- str += token.str;
- break;
- }
- }
- return str;
- }
- function getNegativeAffix(affixTokens, isPrefix) {
- let inFmt = false;
- let str = '';
- for (const token of affixTokens) {
- switch (token.char) {
- case '%':
- case '¤':
- if (isPrefix)
- inFmt = true;
- else
- str = '';
- break;
- case '-':
- if (!inFmt)
- str += '-';
- break;
- case "'":
- if (!inFmt)
- str += token.str;
- break;
- }
- }
- return str;
- }
- /**
- * Parse an {@link
- * http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns |
- * ICU NumberFormatter pattern} string into a {@link Skeleton} structure.
- *
- * @public
- * @param src - The pattern string
- * @param currency - If the pattern includes ¤ tokens, their skeleton
- * representation requires a three-letter currency code.
- * @param onError - Called when the parser encounters a syntax error. The
- * function will still return a {@link Skeleton}, but it will be incomplete
- * and/or inaccurate. If not defined, the error will be thrown instead.
- *
- * @remarks
- * Unlike the skeleton parser, the pattern parser is not able to return partial
- * results on error, and will instead throw. Output padding is not supported.
- *
- * @example
- * ```js
- * import { parseNumberPattern } from '@messageformat/number-skeleton'
- *
- * parseNumberPattern('#,##0.00 ¤', 'EUR', console.error)
- * // {
- * // group: 'group-auto',
- * // precision: {
- * // style: 'precision-fraction',
- * // minFraction: 2,
- * // maxFraction: 2
- * // },
- * // unit: { style: 'currency', currency: 'EUR' }
- * // }
- * ```
- */
- export function parseNumberPattern(src, currency, onError = error => {
- throw error;
- }) {
- const { tokens, negative } = parseTokens(src, onError);
- const res = parseNumberAsSkeleton(tokens.number, onError);
- const prefix = handleAffix(tokens.prefix, res, currency, onError, true);
- const suffix = handleAffix(tokens.suffix, res, currency, onError, false);
- if (negative) {
- const negPrefix = getNegativeAffix(negative.prefix, true);
- const negSuffix = getNegativeAffix(negative.suffix, false);
- res.affix = { pos: [prefix, suffix], neg: [negPrefix, negSuffix] };
- res.sign = 'sign-never';
- }
- else if (prefix || suffix) {
- res.affix = { pos: [prefix, suffix] };
- }
- return res;
- }
|