import { MaskedValueError, PatternError } from '../errors.js'; export function parseNumberAsSkeleton(tokens, onError) { const res = {}; let hasGroups = false; let hasExponent = false; let intOptional = 0; let intDigits = ''; let decimalPos = -1; let fracDigits = ''; let fracOptional = 0; for (let pos = 0; pos < tokens.length; ++pos) { const token = tokens[pos]; switch (token.char) { case '#': { if (decimalPos === -1) { if (intDigits) { const msg = 'Pattern has # after integer digits'; onError(new PatternError('#', msg)); } intOptional += token.width; } else { fracOptional += token.width; } break; } case '0': { if (decimalPos === -1) { intDigits += token.digits; } else { if (fracOptional) { const msg = 'Pattern has digits after # in fraction'; onError(new PatternError('0', msg)); } fracDigits += token.digits; } break; } case '@': { if (res.precision) onError(new MaskedValueError('precision', res.precision)); res.precision = { style: 'precision-fraction', minSignificant: token.min, maxSignificant: token.width }; break; } case ',': hasGroups = true; break; case '.': if (decimalPos === 1) { const msg = 'Pattern has more than one decimal separator'; onError(new PatternError('.', msg)); } decimalPos = pos; break; case 'E': { if (hasExponent) onError(new MaskedValueError('exponent', res.notation)); if (hasGroups) { const msg = 'Exponential patterns may not contain grouping separators'; onError(new PatternError('E', msg)); } res.notation = { style: 'scientific' }; if (token.expDigits > 1) res.notation.expDigits = token.expDigits; if (token.plus) res.notation.expSign = 'sign-always'; hasExponent = true; } } } // imprecise mapping due to paradigm differences if (hasGroups) res.group = 'group-auto'; else if (intOptional + intDigits.length > 3) res.group = 'group-off'; const increment = Number(`${intDigits || '0'}.${fracDigits}`); if (increment) res.precision = { style: 'precision-increment', increment }; if (!hasExponent) { if (intDigits.length > 1) res.integerWidth = { min: intDigits.length }; if (!res.precision && (fracDigits.length || fracOptional)) { res.precision = { style: 'precision-fraction', minFraction: fracDigits.length, maxFraction: fracDigits.length + fracOptional }; } } else { if (!res.precision || increment) { res.integerWidth = intOptional ? { min: 1, max: intOptional + intDigits.length } : { min: Math.max(1, intDigits.length) }; } if (res.precision) { if (!increment) res.integerWidth = { min: 1, max: 1 }; } else { const dc = intDigits.length + fracDigits.length; if (decimalPos === -1) { if (dc > 0) res.precision = { style: 'precision-fraction', maxSignificant: dc }; } else { res.precision = { style: 'precision-fraction', maxSignificant: Math.max(1, dc) + fracOptional }; if (dc > 1) res.precision.minSignificant = dc; } } } return res; }