UNPKG

@parischap/conversions

Version:

A functional library to replace partially the native Intl API

740 lines 34 kB
/** * This module implements a `CVNumberBase10Format` which describes the possible options to * format/parse a base-10 number or `BigDecimal` and implements the formatting/parsing algortithms */ import * as MBigDecimal from '@parischap/effect-lib/MBigDecimal'; import * as MBigInt from '@parischap/effect-lib/MBigInt'; import * as MFunction from '@parischap/effect-lib/MFunction'; import * as MInspectable from '@parischap/effect-lib/MInspectable'; import * as MMatch from '@parischap/effect-lib/MMatch'; import * as MNumber from '@parischap/effect-lib/MNumber'; import * as MPipeable from '@parischap/effect-lib/MPipeable'; import * as MPredicate from '@parischap/effect-lib/MPredicate'; import * as MRegExpString from '@parischap/effect-lib/MRegExpString'; import * as MString from '@parischap/effect-lib/MString'; import * as MStruct from '@parischap/effect-lib/MStruct'; import * as MTypes from '@parischap/effect-lib/MTypes'; import * as Array from 'effect/Array'; import * as BigDecimal from 'effect/BigDecimal'; import * as BigInt from 'effect/BigInt'; import * as Either from 'effect/Either'; import {flow} from 'effect/Function'; import * as Function from 'effect/Function'; import * as Number from 'effect/Number'; import * as Option from 'effect/Option'; import {pipe} from 'effect/Function'; import * as Predicate from 'effect/Predicate'; import * as String from 'effect/String'; import * as Struct from 'effect/Struct'; import * as Tuple from 'effect/Tuple'; import * as CVReal from './Real.js'; import * as CVRoundingMode from './RoundingMode.js'; import * as CVRoundingOption from './RoundingOption.js'; /** * Module tag * * @category Module markers */ export const moduleTag = '@parischap/conversions/NumberBase10Format/'; const _TypeId = /*#__PURE__*/Symbol.for(moduleTag); /** * Type that represents the possible sign display options * * @category Models */ export var SignDisplay; (function (SignDisplay) { /** * Formatting: sign display for negative numbers only, including negative zero. * * Parsing: conversion will fail if a positive sign is used. */ SignDisplay[SignDisplay["Auto"] = 0] = "Auto"; /** * Formatting: sign display for all numbers. * * Parsing: conversion will fail if no sign is present */ SignDisplay[SignDisplay["Always"] = 1] = "Always"; /** * Formatting: sign display for positive and negative numbers, but not zero * * Parsing: conversion will fail if a sign is not present for a value other than 0 or if a sign is * present for 0. */ SignDisplay[SignDisplay["ExceptZero"] = 2] = "ExceptZero"; /** * Formatting: sign display for negative numbers only, excluding negative zero. * * Parsing: conversion will fail if a positive sign is used or if a negative sign is used for 0. */ SignDisplay[SignDisplay["Negative"] = 3] = "Negative"; /** * Formatting: no sign display. * * Parsing: conversion will fail if any sign is present. The number will be treated as positive. */ SignDisplay[SignDisplay["Never"] = 4] = "Never"; })(SignDisplay || (SignDisplay = {})); /** * SignDisplay namespace * * @category Models */ (function (SignDisplay) { const isPlusSign = /*#__PURE__*/MPredicate.strictEquals('+'); const isMinusSign = /*#__PURE__*/MPredicate.strictEquals('-'); const signStringToSignValue = /*#__PURE__*/flow(/*#__PURE__*/Option.liftPredicate(isMinusSign), /*#__PURE__*/Option.as(-1), /*#__PURE__*/Option.getOrElse(/*#__PURE__*/Function.constant(1))); const hasASign = /*#__PURE__*/flow(/*#__PURE__*/Struct.get('sign'), /*#__PURE__*/Option.liftPredicate(String.isNonEmpty), /*#__PURE__*/Option.map(signStringToSignValue)); const hasNoSign = /*#__PURE__*/flow(/*#__PURE__*/Struct.get('sign'), /*#__PURE__*/Option.liftPredicate(String.isEmpty), /*#__PURE__*/Option.map(signStringToSignValue)); const hasNotPlusSign = /*#__PURE__*/flow(/*#__PURE__*/Struct.get('sign'), /*#__PURE__*/Option.liftPredicate(/*#__PURE__*/Predicate.not(isPlusSign)), /*#__PURE__*/Option.map(signStringToSignValue)); /** * Builds a `Parser` implementing `self` * * @category Destructors */ SignDisplay.toParser = /*#__PURE__*/flow(MMatch.make, /*#__PURE__*/MMatch.whenIs(SignDisplay.Auto, /*#__PURE__*/Function.constant(hasNotPlusSign)), /*#__PURE__*/MMatch.whenIs(SignDisplay.Always, /*#__PURE__*/Function.constant(hasASign)), /*#__PURE__*/MMatch.whenIs(SignDisplay.ExceptZero, () => flow(MMatch.make, MMatch.when(MPredicate.struct({ isZero: Function.identity }), hasNoSign), MMatch.orElse(hasASign))), /*#__PURE__*/MMatch.whenIs(SignDisplay.Negative, () => flow(MMatch.make, MMatch.when(MPredicate.struct({ isZero: Function.identity }), hasNoSign), MMatch.orElse(hasNotPlusSign))), /*#__PURE__*/MMatch.whenIs(SignDisplay.Never, /*#__PURE__*/Function.constant(hasNoSign)), MMatch.exhaustive); /** * Builds a `Formatter` implementing `self` * * @category Destructors */ SignDisplay.toFormatter = /*#__PURE__*/flow(MMatch.make, /*#__PURE__*/MMatch.whenIs(SignDisplay.Auto, () => ({ sign }) => sign === -1 ? '-' : ''), /*#__PURE__*/MMatch.whenIs(SignDisplay.Always, () => ({ sign }) => sign === -1 ? '-' : '+'), /*#__PURE__*/MMatch.whenIs(SignDisplay.ExceptZero, () => ({ sign, isZero }) => isZero ? '' : sign === -1 ? '-' : '+'), /*#__PURE__*/MMatch.whenIs(SignDisplay.Negative, () => ({ sign, isZero }) => isZero || sign === 1 ? '' : '-'), /*#__PURE__*/MMatch.whenIs(SignDisplay.Never, () => MFunction.constEmptyString), MMatch.exhaustive); })(SignDisplay || (SignDisplay = {})); /** * Type that represents the possible scientific notation options * * @category Models */ export var ScientificNotation; (function (ScientificNotation) { /** * Formatting: scientific notation is not used. * * Parsing: conversion will fail if a scientific notation is present. */ ScientificNotation[ScientificNotation["None"] = 0] = "None"; /** * Formatting: scientific notation is not used. * * Parsing: scientific notation may be used but is not mandatory. */ ScientificNotation[ScientificNotation["Standard"] = 1] = "Standard"; /** * Formatting: scientific notation is used so that the absolute value of the mantissa m fulfills 1 * ≤ |m| < 10. Number 0 will be displayed as `0e0`. * * Parsing: the conversion will fail if the mantissa is not null and its value m does not fulfill * 1 ≤ |m| < 10. Scientific notation may be used but is not mandatory. A string that does not * contain a scientific notation is deemed equivalent to a string with a null exponent. */ ScientificNotation[ScientificNotation["Normalized"] = 2] = "Normalized"; /** * Formatting: scientific notation is used so that the mantissa m fulfills 1 ≤ |m| < 1000 and the * exponent is a multiple of 3. Number 0 will be displayed as `0e0`. * * Parsing: the conversion will fail if the mantissa is not null and its value m does not fulfill * 1 ≤ |m| < 1000 or if the exponent is not a multiple of 3. Scientific notation may be used but * is not mandatory. A string that does not contain a scientific notation is deemed equivalent to * a string with a null exponent. */ ScientificNotation[ScientificNotation["Engineering"] = 3] = "Engineering"; })(ScientificNotation || (ScientificNotation = {})); /** * ScientificNotation namespace * * @category Models */ (function (ScientificNotation) { const _stringToExponent = /*#__PURE__*/flow(/*#__PURE__*/Option.liftPredicate(String.isNonEmpty), /*#__PURE__*/Option.map(MNumber.unsafeFromString), /*#__PURE__*/Option.orElseSome(/*#__PURE__*/Function.constant(0))); /** * Builds a `Parser` implementing `self` * * @category Destructors */ ScientificNotation.toParser = /*#__PURE__*/flow(MMatch.make, /*#__PURE__*/MMatch.whenIs(ScientificNotation.None, () => flow(Option.liftPredicate(String.isEmpty), Option.as(0))), /*#__PURE__*/MMatch.whenIsOr(ScientificNotation.Standard, ScientificNotation.Normalized, /*#__PURE__*/Function.constant(_stringToExponent)), /*#__PURE__*/MMatch.whenIs(ScientificNotation.Engineering, () => flow(_stringToExponent, Option.filter(MNumber.isMultipleOf(3)))), MMatch.exhaustive); const zeroOrinRange = rangeTop => Predicate.or(BigDecimal.isZero, Predicate.and(BigDecimal.greaterThanOrEqualTo(BigDecimal.unsafeFromNumber(1)), BigDecimal.lessThan(BigDecimal.unsafeFromNumber(rangeTop)))); const zeroOrinOneToTenRange = /*#__PURE__*/zeroOrinRange(10); const zeroOrinOneToOneThousandRange = /*#__PURE__*/zeroOrinRange(1000); /** * Builds a `Parser` implementing `self` * * @category Destructors */ ScientificNotation.toMantissaChecker = /*#__PURE__*/flow(MMatch.make, /*#__PURE__*/MMatch.whenIsOr(ScientificNotation.None, ScientificNotation.Standard, () => Option.some), /*#__PURE__*/MMatch.whenIs(ScientificNotation.Normalized, () => Option.liftPredicate(zeroOrinOneToTenRange)), /*#__PURE__*/MMatch.whenIs(ScientificNotation.Engineering, () => Option.liftPredicate(zeroOrinOneToOneThousandRange)), MMatch.exhaustive); /** * Builds a `Parser` implementing `self` * * @category Destructors */ ScientificNotation.toMantissaAdjuster = /*#__PURE__*/flow(MMatch.make, /*#__PURE__*/MMatch.whenIsOr(ScientificNotation.None, ScientificNotation.Standard, () => flow(Tuple.make, Tuple.appendElement(Option.none()))), /*#__PURE__*/MMatch.whenIs(ScientificNotation.Normalized, () => b => { if (BigDecimal.isZero(b)) return Tuple.make(b, Option.some(0)); const value = b.value; const log10 = MBigInt.unsafeLog10(BigInt.abs(value)); return Tuple.make(BigDecimal.make(value, log10), Option.some(log10 - b.scale)); }), /*#__PURE__*/MMatch.whenIs(ScientificNotation.Engineering, () => b => { if (BigDecimal.isZero(b)) return Tuple.make(b, Option.some(0)); const value = b.value; const log10 = MBigInt.unsafeLog10(BigInt.abs(value)) - b.scale; const correctedLog10 = log10 - MNumber.intModulo(3)(log10); return Tuple.make(BigDecimal.make(value, correctedLog10 + b.scale), Option.some(correctedLog10)); }), MMatch.exhaustive); })(ScientificNotation || (ScientificNotation = {})); /** * Type guard * * @category Guards */ export const has = u => Predicate.hasProperty(u, _TypeId); /** Prototype */ const proto = { [_TypeId]: _TypeId, ... /*#__PURE__*/MInspectable.BaseProto(moduleTag), ...MPipeable.BaseProto }; /** * Constructor * * @category Constructors */ export const make = params => MTypes.objectFromDataAndProto(proto, params); /** * Returns the `thousandSeparator` property of `self` * * @category Destructors */ export const thousandSeparator = /*#__PURE__*/Struct.get('thousandSeparator'); /** * Returns the `fractionalSeparator` property of `self` * * @category Destructors */ export const fractionalSeparator = /*#__PURE__*/Struct.get('fractionalSeparator'); /** * Returns the `showNullIntegerPart` property of `self` * * @category Destructors */ export const showNullIntegerPart = /*#__PURE__*/Struct.get('showNullIntegerPart'); /** * Returns the `minimumFractionalDigits` property of `self` * * @category Destructors */ export const minimumFractionalDigits = /*#__PURE__*/Struct.get('minimumFractionalDigits'); /** * Returns the `maximumFractionalDigits` property of `self` * * @category Destructors */ export const maximumFractionalDigits = /*#__PURE__*/Struct.get('maximumFractionalDigits'); /** * Returns the `eNotationChar` property of `self` * * @category Destructors */ export const eNotationChars = /*#__PURE__*/Struct.get('eNotationChars'); /** * Returns the `scientificNotation` property of `self` * * @category Destructors */ export const scientificNotation = /*#__PURE__*/Struct.get('scientificNotation'); /** * Returns the `roundingMode` property of `self` * * @category Destructors */ export const roundingMode = /*#__PURE__*/Struct.get('roundingMode'); /** * Returns the `signDisplay` property of `self` * * @category Destructors */ export const signDisplay = /*#__PURE__*/Struct.get('signDisplay'); /** * Returns a short description of `self`, e.g. 'signed integer' * * @category Destructors */ export const toDescription = self => { const { thousandSeparator, fractionalSeparator, minimumFractionalDigits, maximumFractionalDigits, scientificNotation, signDisplay } = self; const isInteger = maximumFractionalDigits <= 0; const isUngrouped = thousandSeparator === ''; return pipe(signDisplay, MMatch.make, MMatch.whenIs(SignDisplay.Always, Function.constant('signed ')), MMatch.whenIs(SignDisplay.Never, Function.constant('unsigned ')), MMatch.orElse(Function.constant('potentially signed '))) + (isUngrouped && isInteger ? '' : (isUngrouped || thousandSeparator === ' ') && (fractionalSeparator === ',' || isInteger) ? 'French-style ' : thousandSeparator === '.' && (fractionalSeparator === ',' || isInteger) ? 'Dutch-style ' : (isUngrouped || thousandSeparator === ',') && (fractionalSeparator === '.' || isInteger) ? 'UK-style ' : '') + (isInteger ? 'integer' : minimumFractionalDigits === maximumFractionalDigits ? `${minimumFractionalDigits}-decimal number` : 'number') + pipe(scientificNotation, MMatch.make, MMatch.whenIs(ScientificNotation.None, MFunction.constEmptyString), MMatch.whenIs(ScientificNotation.Standard, Function.constant(' in standard scientific notation')), MMatch.whenIs(ScientificNotation.Normalized, Function.constant(' in normalized scientific notation')), MMatch.whenIs(ScientificNotation.Engineering, Function.constant(' in engineering notation')), MMatch.exhaustive); }; const _toBigDecimalExtractor = (self, fillChar = '') => { const removeThousandSeparator = MString.removeNCharsEveryMCharsFromRight({ m: MRegExpString.DIGIT_GROUP_SIZE, n: self.thousandSeparator.length }); const getParts = MString.matchAndGroups(pipe(self, MStruct.append({ fillChar }), MRegExpString.base10Number, MRegExpString.atStart, RegExp), 5); const signParser = SignDisplay.toParser(self.signDisplay); const exponentParser = ScientificNotation.toParser(self.scientificNotation); const mantissaChecker = ScientificNotation.toMantissaChecker(self.scientificNotation); const fillCharIsZero = fillChar === '0'; return text => Option.gen(function* () { const [match, [signPart, fillChars, mantissaIntegerPart, mantissaFractionalPart, exponentPart]] = yield* getParts(text); const mantissaFractionalPartLength = yield* pipe(mantissaFractionalPart, String.length, Option.liftPredicate(Number.between({ minimum: self.minimumFractionalDigits, maximum: self.maximumFractionalDigits }))); const mantissa = yield* pipe(mantissaIntegerPart, Option.liftPredicate(String.isNonEmpty), Option.match({ // No integer part onNone: () => !self.showNullIntegerPart && mantissaFractionalPartLength !== 0 || fillCharIsZero && fillChars.length !== 0 ? Option.some(MBigDecimal.zero) : Option.none(), // With integer part onSome: flow(self.showNullIntegerPart || mantissaFractionalPartLength === 0 ? Option.some : Option.liftPredicate(Predicate.not(MPredicate.strictEquals('0'))), Option.map(flow(removeThousandSeparator, MBigDecimal.fromPrimitiveOrThrow(0)))) }), Option.map(BigDecimal.sum(pipe(mantissaFractionalPart, Option.liftPredicate(String.isNonEmpty), Option.map(MBigDecimal.fromPrimitiveOrThrow(mantissaFractionalPartLength)), Option.getOrElse(Function.constant(MBigDecimal.zero)))))); const checkedMantissa = yield* mantissaChecker(mantissa); const sign = yield* signParser({ isZero: BigDecimal.isZero(checkedMantissa), sign: signPart }); const exponent = yield* exponentParser(exponentPart); return Tuple.make(BigDecimal.make(checkedMantissa.value, checkedMantissa.scale - exponent), match, sign); }); }; /** * Returns a function that tries to parse, from the start of a string `text`, a number respecting * the options represented by `self` and an optional `fillChar` parameter. If successful, that * function returns a `Some` containing `parsedText` (the part of `text` that could be analyzed as * representing a number) and `value` (`parsedText` converted to a BigDecimal value). Otherwise, it * returns a `None`. As `BigDecimal`'s provide no possibility to distinguish `-0n` and `0n`, parsing * '-0', '0', '+0' will yield the same result. * * `fillChar` is a character that may be used as filler between the sign and the number (or at the * start of the number if it is unsigned). It must be a one-character string (but no error is * triggered if it's not). You can use '0' as `fillChar` but you should not use any other digit * because the value of the number to parse would depend on the number of removed `fillChar`'s. * * @category Parsing */ export const toBigDecimalExtractor = /*#__PURE__*/flow(_toBigDecimalExtractor, /*#__PURE__*/Function.compose(/*#__PURE__*/Option.map(([value, parsedText, sign]) => Tuple.make(BigDecimal.multiply(value, BigDecimal.unsafeFromNumber(sign)), parsedText)))); /** * Same as `toBigDecimalExtractor` but the returned parser throws in case of failure * * @category Parsing */ export const toThrowingBigDecimalExtractor = (self, fillChar) => text => pipe(text, toBigDecimalExtractor(self, fillChar), Option.getOrThrowWith(() => new Error(`A BigDecimal could not be parsed from the start of '${text}'`))); /** * Same as `toBigDecimalExtractor` but returns a `CVReal`. This is the most usual use case. * Furthermore, this function will return `-0` if your parse '-0' and `0` if you parse '0' or '+0'. * * @category Parsing */ export const toRealExtractor = /*#__PURE__*/flow(_toBigDecimalExtractor, /*#__PURE__*/Function.compose(/*#__PURE__*/Option.flatMap(([value, parsedText, sign]) => pipe(value, CVReal.fromBigDecimalOption, Option.map(flow(Number.multiply(sign), Tuple.make, Tuple.appendElement(parsedText))))))); /** * Same as `toRealExtractor` but the returned parser throws in case of failure * * @category Parsing */ export const toThrowingRealExtractor = (self, fillChar) => text => pipe(text, toRealExtractor(self, fillChar), Option.getOrThrowWith(() => new Error(`A Real could not be parsed from the start of '${text}'`))); /** * Same as `toBigDecimalExtractor` but the whole of the input text must represent a number, not just * its start * * @category Parsing */ export const toBigDecimalParser = (self, fillChar) => { const extractor = toBigDecimalExtractor(self, fillChar); return text => pipe(text, extractor, Option.flatMap(flow(Option.liftPredicate(flow(Tuple.getSecond, String.length, MPredicate.strictEquals(text.length))), Option.map(Tuple.getFirst)))); }; /** * Same as `toBigDecimalParser` but the returned parser throws in case of failure * * @category Parsing */ export const toThrowingBigDecimalParser = (self, fillChar) => text => pipe(text, toBigDecimalParser(self, fillChar), Option.getOrThrowWith(() => new Error(`A BigDecimal could not be parsed from '${text}'`))); /** * Same as `toRealExtractor` but the whole of the input text must represent a number, not just its * start * * @category Parsing */ export const toRealParser = (self, fillChar) => { const extractor = toRealExtractor(self, fillChar); return text => pipe(text, extractor, Option.flatMap(flow(Option.liftPredicate(flow(Tuple.getSecond, String.length, MPredicate.strictEquals(text.length))), Option.map(Tuple.getFirst)))); }; /** * Same as `toRealParser` but the returned parser throws in case of failure * * @category Parsing */ export const toThrowingRealParser = (self, fillChar) => text => pipe(text, toRealParser(self, fillChar), Option.getOrThrowWith(() => new Error(`A Real could not be parsed from '${text}'`))); /** * Returns a function that tries to format a `number` respecting the options represented by * `self`and an optional parameter `fillChars`. If successful, that function returns a `Some` of the * formatted number. Otherwise, it returns a `None`. `number` can be of type number or `BigDecimal` * for better accuracy. There is a difference between number and `BigDecimal` (and bigint) regarding * the sign of 0. In Javascript, Object.is(0,-0) is false whereas Object.is(0n,-0n) is true. So if * the sign of zero is important to you, prefer passing a number to the function. `0` as a * BigDecimal will always be interpreted as a positive `0` as we have no means of knowing if it is * negative or positive. * * `fillChars` is a string whose first characters will be inserted between the sign and the number * (or at the start of the number if it is unsigned) so that the formatted number has at least the * same number of characters as fillChars (e.g. the result will be '-02' if you try to format the * value -2 with fillChars = '000') * * @category Formatting */ export const toNumberFormatter = (self, fillChars = '') => { const rounder = self.maximumFractionalDigits === +Infinity ? Function.identity : pipe({ precision: self.maximumFractionalDigits, roundingMode: self.roundingMode }, CVRoundingOption.make, CVRoundingOption.toBigDecimalRounder); const signFormatter = SignDisplay.toFormatter(self.signDisplay); const mantissaAdjuster = ScientificNotation.toMantissaAdjuster(self.scientificNotation); const hasThousandSeparator = self.thousandSeparator !== ''; const eNotationChar = pipe(self.eNotationChars, Array.get(0), Option.getOrElse(MFunction.constEmptyString)); const takeNFirstCharsOfFillChars = MFunction.flipDual(String.takeLeft)(fillChars); return number => { const [sign, selfAsBigDecimal] = MTypes.isNumber(number) ? Tuple.make(number < 0 || Object.is(-0, number) ? -1 : 1, BigDecimal.unsafeFromNumber(number)) : Tuple.make(number.value < 0 ? -1 : 1, number); const [adjusted, exponent] = mantissaAdjuster(selfAsBigDecimal); const absRounded = pipe(adjusted, rounder, BigDecimal.abs); const [integerPart, fractionalPart] = pipe(absRounded, MBigDecimal.truncatedAndFollowingParts()); const signString = signFormatter({ sign, isZero: BigDecimal.isZero(absRounded) }); const normalizedFractionalPart = BigDecimal.normalize(fractionalPart); const fractionalPartString = pipe(normalizedFractionalPart.value, Option.liftPredicate(Predicate.not(MBigInt.isZero)), Option.map(MString.fromNonNullablePrimitive), Option.getOrElse(MFunction.constEmptyString), String.padStart(normalizedFractionalPart.scale, '0'), String.padEnd(self.minimumFractionalDigits, '0'), Option.liftPredicate(String.isNonEmpty), Option.map(MString.prepend(self.fractionalSeparator)), Option.getOrElse(MFunction.constEmptyString)); const integerPartString = pipe(integerPart.value.toString(), MFunction.fIfTrue({ condition: hasThousandSeparator, f: flow(MString.splitEquallyRestAtStart(MRegExpString.DIGIT_GROUP_SIZE), Array.intersperse(self.thousandSeparator), Array.join('')) }), Either.liftPredicate(Predicate.not(MPredicate.strictEquals('0')), MFunction.fIfTrue({ condition: !self.showNullIntegerPart && fractionalPartString.length !== 0, f: MFunction.constEmptyString })), Either.merge); const exponentString = pipe(exponent, Option.map(flow(MString.fromNumber(10), MString.prepend(eNotationChar))), Option.getOrElse(MFunction.constEmptyString)); const numberString = integerPartString + fractionalPartString + exponentString; const pad = pipe(fillChars.length, Number.subtract(signString.length), Number.subtract(numberString.length), Number.max(0), takeNFirstCharsOfFillChars); return signString + pad + numberString; }; }; /** * Returns a copy of `self` with `minimumFractionalDigits` and `maximumFractionalDigits` set to `n`. * `n` must be a finite positive integer * * @category Modifiers */ export const withNDecimals = decimalNumber => flow(MStruct.append({ minimumFractionalDigits: decimalNumber, maximumFractionalDigits: decimalNumber }), make); /** * Returns a copy of `self` with `maximumFractionalDigits` set to `n`. `n` must be a positive * integer (`+Infinity` allowed). Pass 0 for an integer format * * @category Modifiers */ export const withMaxNDecimals = maxDecimalNumber => self => pipe(self, MStruct.append({ minimumFractionalDigits: Math.min(self.minimumFractionalDigits, maxDecimalNumber), maximumFractionalDigits: maxDecimalNumber }), make); /** * Returns a copy of `self` with `minimumFractionalDigits` set to `n`. `n` must be a finite positive * integer * * @category Modifiers */ export const withMinNDecimals = minDecimalNumber => self => pipe(self, MStruct.append({ minimumFractionalDigits: minDecimalNumber, maximumFractionalDigits: Math.max(self.maximumFractionalDigits, minDecimalNumber) }), make); /** * Returns a copy of `self` with `scientificNotation` set to `None` * * @category Modifiers */ export const withNoScientificNotation = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ scientificNotation: ScientificNotation.None }), make); /** * Returns a copy of `self` with `scientificNotation` set to `Standard` * * @category Modifiers */ export const withStandardScientificNotation = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ scientificNotation: ScientificNotation.Standard }), make); /** * Returns a copy of `self` with `scientificNotation` set to `Normalized` * * @category Modifiers */ export const withNormalizedScientificNotation = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ scientificNotation: ScientificNotation.Normalized }), make); /** * Returns a copy of `self` with `scientificNotation` set to `Engineering` * * @category Modifiers */ export const withEngineeringScientificNotation = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ scientificNotation: ScientificNotation.Engineering }), make); /** * Returns a copy of `self` with `thousandSeparator` set to `thousandSeparator` * * @category Modifiers */ export const withThousandSeparator = thousandSeparator => flow(MStruct.append({ thousandSeparator }), make); /** * Returns a copy of `self` with `thousandSeparator` set to '' * * @category Modifiers */ export const withoutThousandSeparator = /*#__PURE__*/withThousandSeparator(''); /** * Returns a copy of `self` with `fractionalSeparator` set to `fractionalSeparator` * * @category Modifiers */ export const withFractionalSeparator = fractionalSeparator => flow(MStruct.append({ fractionalSeparator: fractionalSeparator }), make); /** * Returns a copy of `self` with `signDisplay` set to `Auto` * * @category Modifiers */ export const withSignDisplayForNegative = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ signDisplay: SignDisplay.Auto }), make); /** * Returns a copy of `self` with `signDisplay` set to `Always` * * @category Modifiers */ export const withSignDisplay = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ signDisplay: SignDisplay.Always }), make); /** * Returns a copy of `self` with `signDisplay` set to `ExceptZero` * * @category Modifiers */ export const withSignDisplayExceptZero = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ signDisplay: SignDisplay.ExceptZero }), make); /** * Returns a copy of `self` with `signDisplay` set to `Negative` * * @category Modifiers */ export const withSignDisplayForNegativeExceptZero = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ signDisplay: SignDisplay.Negative }), make); /** * Returns a copy of `self` with `signDisplay` set to `Never` * * @category Modifiers */ export const withoutSignDisplay = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ signDisplay: SignDisplay.Never }), make); /** * Returns a copy of `self` with `roundingMode` set to `Ceil` * * @category Modifiers */ export const withCeilRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.Ceil }), make); /** * Returns a copy of `self` with `roundingMode` set to `Floor` * * @category Modifiers */ export const withFloorRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.Floor }), make); /** * Returns a copy of `self` with `roundingMode` set to `Expand` * * @category Modifiers */ export const withExpandRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.Expand }), make); /** * Returns a copy of `self` with `roundingMode` set to `Trunc` * * @category Modifiers */ export const withTruncRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.Trunc }), make); /** * Returns a copy of `self` with `roundingMode` set to `HalfCeil` * * @category Modifiers */ export const withHalfCeilRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.HalfCeil }), make); /** * Returns a copy of `self` with `roundingMode` set to `HalfFloor` * * @category Modifiers */ export const withHalfFloorRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.HalfFloor }), make); /** * Returns a copy of `self` with `roundingMode` set to `HalfExpand` * * @category Modifiers */ export const withHalfExpandRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.HalfExpand }), make); /** * Returns a copy of `self` with `roundingMode` set to `HalfTrunc` * * @category Modifiers */ export const withHalfTruncRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.HalfTrunc }), make); /** * Returns a copy of `self` with `roundingMode` set to `HalfEven` * * @category Modifiers */ export const withHalfEvenRoundingMode = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ roundingMode: CVRoundingMode.Type.HalfEven }), make); /** * Returns a copy of `self` with `showNullIntegerPart` set to `false` * * @category Modifiers */ export const withNullIntegerPartNotShowing = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ showNullIntegerPart: false }), make); /** * Returns a copy of `self` with `showNullIntegerPart` set to `true` * * @category Modifiers */ export const withNullIntegerPartShowing = /*#__PURE__*/flow(/*#__PURE__*/MStruct.append({ showNullIntegerPart: true }), make); /** * `CVNumberBase10Format` instance that uses a comma as fractional separator, a space as thousand * separator and shows at most three fractional digits. Used in countries like France, * French-speaking Canada, French-speaking Belgium, Denmark, Finland, Sweden... * * @category Instances */ export const frenchStyleNumber = /*#__PURE__*/make({ thousandSeparator: ' ', fractionalSeparator: ',', showNullIntegerPart: true, minimumFractionalDigits: 0, maximumFractionalDigits: 3, eNotationChars: ['e', 'E'], scientificNotation: ScientificNotation.None, roundingMode: CVRoundingMode.Type.HalfExpand, signDisplay: SignDisplay.Negative }); /** * `CVNumberBase10Format` instance that uses a comma as fractional separator, no thousand separator * and shows at most three fractional digits. Used in countries like France, French-speaking Canada, * French-speaking Belgium, Denmark, Finland, Sweden... * * @category Instances */ export const frenchStyleUngroupedNumber = /*#__PURE__*/pipe(frenchStyleNumber, withoutThousandSeparator); /** * French-style integer `CVNumberBase10Format` instance. Used in countries like France, * French-speaking Canada, French-speaking Belgium, Denmark, Finland, Sweden... * * @category Instances */ export const frenchStyleInteger = /*#__PURE__*/pipe(frenchStyleNumber, /*#__PURE__*/withMaxNDecimals(0)); /** * `CVNumberBase10Format` instance that uses a comma as fractional separator, a dot as thousand * separator and shows at most three fractional digits. Used in countries like Dutch-speaking * Belgium, the Netherlands, Germany, Italy, Norway, Croatia, Spain... * * @category Instances */ export const dutchStyleNumber = /*#__PURE__*/pipe(frenchStyleNumber, /*#__PURE__*/MStruct.append({ thousandSeparator: '.' }), make); /** * `CVNumberBase10Format` instance that uses a comma as fractional separator, no thousand separator * and shows at most three fractional digits. Used in countries like Dutch-speaking Belgium, the * Netherlands, Germany, Italy, Norway, Croatia, Spain... * * @category Instances */ export const dutchStyleUngroupedNumber = /*#__PURE__*/pipe(dutchStyleNumber, withoutThousandSeparator); /** * Dutch-style integer `CVNumberBase10Format` instance. Used in countries like Dutch-speaking * Belgium, the Netherlands, Germany, Italy, Norway, Croatia, Spain... * * @category Instances */ export const dutchStyleInteger = /*#__PURE__*/pipe(dutchStyleNumber, /*#__PURE__*/withMaxNDecimals(0)); /** * `CVNumberBase10Format` instance that uses a dot as fractional separator, a comma as thousand * separator and shows at most three fractional digits. Used in countries like the UK, the US, * English-speaking Canada, Australia, Thaïland, Bosnia... * * @category Instances */ export const ukStyleNumber = /*#__PURE__*/pipe(frenchStyleNumber, /*#__PURE__*/MStruct.append({ fractionalSeparator: '.', thousandSeparator: ',' }), make); /** * `CVNumberBase10Format` instance that uses a dot as fractional separator, no thousand separator * and shows at most three fractional digits. Used in countries like the UK, the US, * English-speaking Canada, Australia, Thaïland, Bosnia... * * @category Instances */ export const ukStyleUngroupedNumber = /*#__PURE__*/pipe(ukStyleNumber, withoutThousandSeparator); /** * Uk-style integer `CVNumberBase10Format` instance. Used in countries like the UK, the US, * English-speaking Canada, Australia, Thaïland, Bosnia... * * @category Instances */ export const ukStyleInteger = /*#__PURE__*/pipe(ukStyleNumber, /*#__PURE__*/withMaxNDecimals(0)); /** * Integer `CVNumberBase10Format` instance with no thousand separator * * @category Instances */ export const integer = /*#__PURE__*/pipe(frenchStyleInteger, withoutThousandSeparator); //# sourceMappingURL=NumberBase10Format.js.map