Skip to content

Commit

Permalink
refactor(kit): improve internal toNumberParts utility (#1210)
Browse files Browse the repository at this point in the history
  • Loading branch information
nsbarsukov authored Apr 23, 2024
1 parent 96391da commit e993783
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 33 deletions.
3 changes: 1 addition & 2 deletions projects/kit/src/lib/masks/number/number-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ export function maskitoNumberOptionsGenerator({
thousandSeparator,
prefix,
postfix,
minusSign,
}),
createDecimalZeroPaddingPostprocessor({
decimalSeparator,
Expand All @@ -153,7 +152,7 @@ export function maskitoNumberOptionsGenerator({
prefix,
postfix,
}),
emptyPostprocessor({prefix, postfix, decimalSeparator}),
emptyPostprocessor({prefix, postfix, decimalSeparator, thousandSeparator}),
],
plugins: [
createLeadingZeroesValidationPlugin({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@ export function emptyPostprocessor({
prefix,
postfix,
decimalSeparator,
thousandSeparator,
}: {
prefix: string;
postfix: string;
decimalSeparator: string;
thousandSeparator: string;
}): MaskitoPostprocessor {
return ({value, selection}) => {
const [caretIndex] = selection;
const {cleanValue, extractedPrefix, extractedPostfix} = extractAffixes(value, {
prefix,
postfix,
});
const {minus, integerPart, decimalPart} = toNumberParts(
cleanValue,
const {minus, integerPart, decimalPart} = toNumberParts(cleanValue, {
decimalSeparator,
);
thousandSeparator,
});
const aloneDecimalSeparator =
!integerPart && !decimalPart && cleanValue.includes(decimalSeparator);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {MaskitoPostprocessor} from '@maskito/core';

import {extractAffixes, identity} from '../../../utils';
import {toNumberParts} from '../utils';

/**
* It adds symbol for separating thousands.
Expand All @@ -11,13 +12,11 @@ export function createThousandSeparatorPostprocessor({
decimalSeparator,
prefix,
postfix,
minusSign,
}: {
thousandSeparator: string;
decimalSeparator: string;
prefix: string;
postfix: string;
minusSign: string;
}): MaskitoPostprocessor {
if (!thousandSeparator) {
return identity;
Expand All @@ -31,9 +30,10 @@ export function createThousandSeparatorPostprocessor({
postfix,
});

const [integerPart, decimalPart = ''] = cleanValue
.replace(minusSign, '')
.split(decimalSeparator);
const {minus, integerPart, decimalPart} = toNumberParts(cleanValue, {
decimalSeparator,
thousandSeparator,
});
const [initialFrom, initialTo] = selection;
let [from, to] = selection;

Expand Down Expand Up @@ -84,7 +84,7 @@ export function createThousandSeparatorPostprocessor({
return {
value:
extractedPrefix +
(cleanValue.includes(minusSign) ? minusSign : '') +
minus +
processedIntegerPart +
(cleanValue.includes(decimalSeparator) ? decimalSeparator : '') +
decimalPart +
Expand Down
119 changes: 100 additions & 19 deletions projects/kit/src/lib/masks/number/utils/tests/to-number-parts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {toNumberParts} from '../to-number-parts';
describe('toNumberParts', () => {
[',', '.'].forEach(decimalSeparator => {
describe(`decimalSeparator = ${decimalSeparator}`, () => {
const thousandSeparator = '_';

it('empty string => empty parts', () => {
expect(toNumberParts('', decimalSeparator)).toEqual({
expect(toNumberParts('', {decimalSeparator, thousandSeparator})).toEqual({
minus: '',
integerPart: '',
decimalPart: '',
Expand All @@ -20,7 +22,10 @@ describe('toNumberParts', () => {

it(`123${decimalSeparator}45 => {minus: "", integerPart: "123", decimalPart: "45"}`, () => {
expect(
toNumberParts(`123${decimalSeparator}45`, decimalSeparator),
toNumberParts(`123${decimalSeparator}45`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '',
integerPart: '123',
Expand All @@ -30,7 +35,10 @@ describe('toNumberParts', () => {

it(`-123${decimalSeparator}45 => {minus: "-", integerPart: "123", decimalPart: "45"}`, () => {
expect(
toNumberParts(`-123${decimalSeparator}45`, decimalSeparator),
toNumberParts(`-123${decimalSeparator}45`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '-',
integerPart: '123',
Expand All @@ -39,58 +47,131 @@ describe('toNumberParts', () => {
});

it('123 => {minus: "", integerPart: "123", decimalPart: ""}', () => {
expect(toNumberParts('123', decimalSeparator)).toEqual({
expect(
toNumberParts('123', {decimalSeparator, thousandSeparator}),
).toEqual({
minus: '',
integerPart: '123',
decimalPart: '',
});
});

it('-123 => {minus: "-", integerPart: "123", decimalPart: ""}', () => {
expect(toNumberParts('-123', decimalSeparator)).toEqual({
expect(
toNumberParts('-123', {decimalSeparator, thousandSeparator}),
).toEqual({
minus: '-',
integerPart: '123',
decimalPart: '',
});
});

it(`${decimalSeparator}45 => {minus: "", integerPart: "", decimalPart: "45"}`, () => {
expect(toNumberParts(`${decimalSeparator}45`, decimalSeparator)).toEqual({
expect(
toNumberParts(`${decimalSeparator}45`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '',
integerPart: '',
decimalPart: '45',
});
});

it(`-${decimalSeparator}45 => {minus: "-", integerPart: "", decimalPart: "45"}`, () => {
expect(toNumberParts(`-${decimalSeparator}45`, decimalSeparator)).toEqual(
expect(
toNumberParts(`-${decimalSeparator}45`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '-',
integerPart: '',
decimalPart: '45',
});
});

it('- => {minus: "-", integerPart: "", decimalPart: ""}', () => {
expect(toNumberParts('-', {decimalSeparator, thousandSeparator})).toEqual(
{
minus: '-',
integerPart: '',
decimalPart: '45',
decimalPart: '',
},
);
});

it('- => {minus: "-", integerPart: "", decimalPart: ""}', () => {
expect(toNumberParts('-', decimalSeparator)).toEqual({
minus: '-',
integerPart: '',
decimalPart: '',
});
});
});
});

it('different minus signs', () => {
[CHAR_MINUS, CHAR_HYPHEN, CHAR_EN_DASH, CHAR_EM_DASH, CHAR_JP_HYPHEN].forEach(
minus => {
expect(toNumberParts(`${minus}123.45`, '.')).toEqual({
expect(
toNumberParts(`${minus}1,234,567.89`, {
decimalSeparator: '.',
thousandSeparator: ',',
}),
).toEqual({
minus,
integerPart: '123',
decimalPart: '45',
integerPart: '1,234,567',
decimalPart: '89',
});
},
);
});

describe('thousand separator (e.g. underscore) is a part of integer', () => {
const thousandSeparator = '_';
const decimalSeparator = '.';

it('only thousand separator sign', () => {
expect(
toNumberParts(thousandSeparator, {decimalSeparator, thousandSeparator}),
).toEqual({
minus: '',
integerPart: thousandSeparator,
decimalPart: '',
});
});

it('only minus and thousand separator signs', () => {
expect(
toNumberParts(`-${thousandSeparator}`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '-',
integerPart: thousandSeparator,
decimalPart: '',
});
});

it(`-1${thousandSeparator}234.45 => {minus: "-", integerPart: "1${thousandSeparator}234", decimalPart: "45"}`, () => {
expect(
toNumberParts(`-1${thousandSeparator}234.45`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '-',
integerPart: `1${thousandSeparator}234`,
decimalPart: '45',
});
});

it(`-${thousandSeparator}234.45 => {minus: "-", integerPart: "${thousandSeparator}234", decimalPart: "45"}`, () => {
expect(
toNumberParts(`-${thousandSeparator}234.45`, {
decimalSeparator,
thousandSeparator,
}),
).toEqual({
minus: '-',
integerPart: `${thousandSeparator}234`,
decimalPart: '45',
});
});
});
});
11 changes: 8 additions & 3 deletions projects/kit/src/lib/masks/number/utils/to-number-parts.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
const EXTRACT_MINUS_RE = /(\D)?(.*)/;
import {escapeRegExp} from '../../../utils';

export function toNumberParts(
value: string,
decimalSeparator: string,
{
decimalSeparator,
thousandSeparator,
}: {decimalSeparator: string; thousandSeparator: string},
): {minus: string; integerPart: string; decimalPart: string} {
const [integerWithMinus = '', decimalPart = ''] = value.split(decimalSeparator);
const [, minus = '', integerPart = ''] =
integerWithMinus.match(EXTRACT_MINUS_RE) || [];
integerWithMinus.match(
new RegExp(`([^\\d${escapeRegExp(thousandSeparator)}]+)?(.*)`),
) || [];

return {minus, integerPart, decimalPart};
}

0 comments on commit e993783

Please sign in to comment.