Browse Source

Update documentation, types

Add features and limitations to the project.

Also update the types to be stricter.
master
TheoryOfNekomata 1 year ago
parent
commit
fa9c981c07
9 changed files with 109 additions and 64 deletions
  1. +19
    -0
      README.md
  2. +2
    -2
      TODO.md
  3. +33
    -2
      packages/core/src/common.ts
  4. +8
    -22
      packages/core/src/converter.ts
  5. +9
    -6
      packages/core/src/exponent.ts
  6. +13
    -10
      packages/core/src/systems/en-UK/long-count/parse.ts
  7. +6
    -6
      packages/core/src/systems/en-UK/long-count/stringify.ts
  8. +13
    -10
      packages/core/src/systems/en-US/short-count/parse.ts
  9. +6
    -6
      packages/core/src/systems/en-US/short-count/stringify.ts

+ 19
- 0
README.md View File

@@ -5,3 +5,22 @@ Get the name of a number, even if it's stupidly big.
## References ## References


* [How high can you count?](http://www.isthe.com/chongo/tech/math/number/howhigh.html) * [How high can you count?](http://www.isthe.com/chongo/tech/math/number/howhigh.html)

## Features

* Stringify/parse numbers and names in American/British short count (e.g. "million", "billion", "trillion"), or European
(e.g. "million", "milliard", "billion", "billiard", "trillion", "trilliard").
* Support for exponential notation, even if in non-standard form (e.g. `123.45e+5`).
* Support for negative numbers.

See [TODO.md](TODO.md) for a list of features that are planned for implementation.

## Limitations

* Can only stringify and parse numbers and names that resolve to integer values.
* Exponents `x` in values are limited to `Number.MAX_SAFE_INTEGER >~ x >~ Number.MIN_SAFE_INTEGER`.
Values may exceed extremes such as `Number.MAX_SAFE_INTEGER` and `Number.EPSILON` in which loss of
precision may occur.
* No support for arbitrary number names such as "googol".
* No support for fractional number names such as "half", "quarter", "third", "tenth", etc.
* Supports only native types (`bigint`, `string`, `number`).

+ 2
- 2
TODO.md View File

@@ -1,3 +1,3 @@
- [ ] Ordinals - [ ] Ordinals
- [ ] Fractions
- [ ] Other locales (long count, languages, etc.)
- [ ] ~~Fractions~~
- [X] Other locales (long count, languages, etc.)

+ 33
- 2
packages/core/src/common.ts View File

@@ -1,7 +1,9 @@
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';

/** /**
* Group digits. * Group digits.
*/ */
type GroupDigits = string;
export type GroupDigits = `${Digit}${Digit}${Digit}`;


/** /**
* Group place. * Group place.
@@ -102,7 +104,7 @@ export interface NumberNameSystem {
* Parses groups from a string. * Parses groups from a string.
* @param tokens - The string to parse groups from. * @param tokens - The string to parse groups from.
* @see {NumberNameSystem.stringifyGroups} * @see {NumberNameSystem.stringifyGroups}
* @returns Group[] The parsed groups.
* @returns ParseResult The parsed groups as well as an indicator if the number is Boolean.
*/ */
parseGroups: (tokens: string[]) => ParseResult; parseGroups: (tokens: string[]) => ParseResult;
/** /**
@@ -115,6 +117,25 @@ export interface NumberNameSystem {
combineGroups: (groups: Group[], negative: boolean) => string; combineGroups: (groups: Group[], negative: boolean) => string;
} }


/**
* Allowed value type for {@link stringify}.
*/
export type AllowedValue = string | number | bigint;

/**
* Array of allowed types for {@link parse}.
*/
export const ALLOWED_PARSE_RESULT_TYPES = [
'string',
'number',
'bigint',
] as const;

/**
* Allowed type for {@link parse}.
*/
export type ParseResultType = typeof ALLOWED_PARSE_RESULT_TYPES[number];

/** /**
* Error thrown when an invalid token is encountered. * Error thrown when an invalid token is encountered.
*/ */
@@ -124,6 +145,11 @@ export class InvalidTokenError extends Error {
} }
} }


/**
* Gets the maximum value from a list of bigints.
* @param b - The bigints to get the maximum value from.
* @returns bigint The maximum value.
*/
export const bigIntMax = (...b: bigint[]) => b.reduce( export const bigIntMax = (...b: bigint[]) => b.reduce(
(previousMax, current) => { (previousMax, current) => {
if (typeof previousMax === 'undefined') { if (typeof previousMax === 'undefined') {
@@ -134,6 +160,11 @@ export const bigIntMax = (...b: bigint[]) => b.reduce(
undefined as bigint | undefined, undefined as bigint | undefined,
); );


/**
* Gets the minimum value from a list of bigints.
* @param b - The bigints to get the minimum value from.
* @returns bigint The minimum value.
*/
export const bigIntMin = (...b: bigint[]) => b.reduce( export const bigIntMin = (...b: bigint[]) => b.reduce(
(previousMin, current) => { (previousMin, current) => {
if (typeof previousMin === 'undefined') { if (typeof previousMin === 'undefined') {


+ 8
- 22
packages/core/src/converter.ts View File

@@ -1,5 +1,10 @@
import { enUS } from './systems'; import { enUS } from './systems';
import { NumberNameSystem } from './common';
import {
ALLOWED_PARSE_RESULT_TYPES,
AllowedValue,
NumberNameSystem,
ParseResultType,
} from './common';
import { exponentialToNumberString, extractExponentialComponents, numberToExponential } from './exponent'; import { exponentialToNumberString, extractExponentialComponents, numberToExponential } from './exponent';


/** /**
@@ -12,25 +17,6 @@ const NEGATIVE_SYMBOL = '-' as const;
*/ */
const EXPONENT_DELIMITER = 'e' as const; const EXPONENT_DELIMITER = 'e' as const;


/**
* Allowed value type for {@link stringify}.
*/
export type AllowedValue = string | number | bigint;

/**
* Array of allowed types for {@link parse}.
*/
const ALLOWED_PARSE_RESULT_TYPES = [
'string',
'number',
'bigint',
] as const;

/**
* Allowed type for {@link parse}.
*/
type ParseResult = typeof ALLOWED_PARSE_RESULT_TYPES[number];

/** /**
* Options to use when converting a value to a string. * Options to use when converting a value to a string.
*/ */
@@ -104,7 +90,7 @@ export interface ParseOptions {
/** /**
* The type to parse the value as. * The type to parse the value as.
*/ */
type?: ParseResult;
type?: ParseResultType;
} }


/** /**
@@ -115,7 +101,7 @@ export interface ParseOptions {
*/ */
export const parse = (value: string, options = {} as ParseOptions) => { export const parse = (value: string, options = {} as ParseOptions) => {
const { system = enUS.shortCount, type: typeRaw = 'string' } = options; const { system = enUS.shortCount, type: typeRaw = 'string' } = options;
const type = typeRaw.trim().toLowerCase() as ParseResult;
const type = typeRaw.trim().toLowerCase() as ParseResultType;


if (!((ALLOWED_PARSE_RESULT_TYPES as unknown as string[]).includes(type))) { if (!((ALLOWED_PARSE_RESULT_TYPES as unknown as string[]).includes(type))) {
throw new TypeError(`Return type must be a string, number, or bigint. Received: ${type}`); throw new TypeError(`Return type must be a string, number, or bigint. Received: ${type}`);


+ 9
- 6
packages/core/src/exponent.ts View File

@@ -1,7 +1,4 @@
/**
* Valid values that can be converted to exponential notation.
*/
export type ValidValue = string | number | bigint;
import { AllowedValue } from './common';


interface BaseOptions { interface BaseOptions {
/** /**
@@ -158,13 +155,13 @@ export const extractExponentialComponents = (
}; };


/** /**
* Converts a numeric value to a string in exponential notation. Supports numbers of all types.
* Converts a numeric value to a string in exponential notation.
* @param value - The value to convert. * @param value - The value to convert.
* @param options - Options to use when extracting components. * @param options - Options to use when extracting components.
* @returns string The value in exponential notation. * @returns string The value in exponential notation.
*/ */
export const numberToExponential = ( export const numberToExponential = (
value: ValidValue,
value: AllowedValue,
options = {} as NumberToExponentialOptions, options = {} as NumberToExponentialOptions,
): string => { ): string => {
const valueRaw = value as unknown; const valueRaw = value as unknown;
@@ -216,6 +213,12 @@ export const numberToExponential = (
return `${significandInteger}${decimalPoint}${significandFractional}${exponentDelimiter}${exponent}`; return `${significandInteger}${decimalPoint}${significandFractional}${exponentDelimiter}${exponent}`;
}; };


/**
* Converts a string in exponential notation (e.g. 1e+2) to a number string (e.g. 100).
* @param exp - The number in exponential notation to convert.
* @param options - Options to use when converting number strings.
* @returns string The number string.
*/
export const exponentialToNumberString = ( export const exponentialToNumberString = (
exp: string, exp: string,
options = {} as ExponentialToNumberStringOptions, options = {} as ExponentialToNumberStringOptions,


+ 13
- 10
packages/core/src/systems/en-UK/long-count/parse.ts View File

@@ -2,7 +2,7 @@ import {
bigIntMax, bigIntMin, bigIntMax, bigIntMin,
Group, Group,
GROUP_DIGITS_INDEX, GROUP_DIGITS_INDEX,
GROUP_PLACE_INDEX,
GROUP_PLACE_INDEX, GroupDigits,
InvalidTokenError, InvalidTokenError,
} from '../../../common'; } from '../../../common';
import { import {
@@ -269,14 +269,14 @@ const parseThousand = (acc: ParserState, token: string): ParserState => {
if (acc.mode === ParseGroupsMode.ONES_MODE) { if (acc.mode === ParseGroupsMode.ONES_MODE) {
const ones = ONES.findIndex((o) => o === acc.lastToken); const ones = ONES.findIndex((o) => o === acc.lastToken);
if (ones > -1) { if (ones > -1) {
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}`;
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}` as GroupDigits;
} }
} else if (acc.mode === ParseGroupsMode.TENS_MODE) { } else if (acc.mode === ParseGroupsMode.TENS_MODE) {
const tens = TENS.findIndex((t) => t === acc.lastToken); const tens = TENS.findIndex((t) => t === acc.lastToken);
if (tens > -1) { if (tens > -1) {
lastGroup[GROUP_DIGITS_INDEX] = ( lastGroup[GROUP_DIGITS_INDEX] = (
`${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`
);
) as GroupDigits;
} }
} }


@@ -294,7 +294,7 @@ const parseThousand = (acc: ParserState, token: string): ParserState => {
const parseHundred = (acc: ParserState): ParserState => { const parseHundred = (acc: ParserState): ParserState => {
const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE];
const hundreds = ONES.findIndex((o) => o === acc.lastToken); const hundreds = ONES.findIndex((o) => o === acc.lastToken);
lastGroup[GROUP_DIGITS_INDEX] = `${hundreds}${lastGroup[GROUP_DIGITS_INDEX].slice(1)}`;
lastGroup[GROUP_DIGITS_INDEX] = `${hundreds}${lastGroup[GROUP_DIGITS_INDEX].slice(1)}` as GroupDigits;
return { return {
...acc, ...acc,
groups: [...acc.groups.slice(0, -1), lastGroup], groups: [...acc.groups.slice(0, -1), lastGroup],
@@ -308,7 +308,7 @@ const parseFinal = (acc: ParserState): ParserState => {
if (acc.mode === ParseGroupsMode.ONES_MODE) { if (acc.mode === ParseGroupsMode.ONES_MODE) {
const ones = ONES.findIndex((o) => o === acc.lastToken); const ones = ONES.findIndex((o) => o === acc.lastToken);
if (ones > -1) { if (ones > -1) {
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}`;
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}` as GroupDigits;
} }
// We assume last token without parsed place will always be the smallest // We assume last token without parsed place will always be the smallest
lastGroup[GROUP_PLACE_INDEX] = BigInt(0); lastGroup[GROUP_PLACE_INDEX] = BigInt(0);
@@ -322,7 +322,9 @@ const parseFinal = (acc: ParserState): ParserState => {
if (acc.mode === ParseGroupsMode.TENS_MODE) { if (acc.mode === ParseGroupsMode.TENS_MODE) {
const tens = TENS.findIndex((o) => o === acc.lastToken); const tens = TENS.findIndex((o) => o === acc.lastToken);
if (tens > -1) { if (tens > -1) {
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[0].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`;
lastGroup[GROUP_DIGITS_INDEX] = (
`${lastGroup[0].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`
) as GroupDigits;
} }
lastGroup[GROUP_PLACE_INDEX] = BigInt(0); lastGroup[GROUP_PLACE_INDEX] = BigInt(0);
return { return {
@@ -360,11 +362,11 @@ const parseTenPlusOnes = (acc: ParserState, token: string): ParserState => {
...acc, ...acc,
lastToken: token, lastToken: token,
mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, mode: ParseGroupsMode.TEN_PLUS_ONES_MODE,
groups: [...acc.groups, [`01${tenPlusOnes}`, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
groups: [...acc.groups, [`01${tenPlusOnes}` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
}; };
} }


lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}`;
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}` as GroupDigits;
return { return {
...acc, ...acc,
lastToken: token, lastToken: token,
@@ -381,13 +383,14 @@ const parseTens = (acc: ParserState, token: string): ParserState => {
...acc, ...acc,
lastToken: token, lastToken: token,
mode: ParseGroupsMode.TENS_MODE, mode: ParseGroupsMode.TENS_MODE,
groups: [...acc.groups, [`0${tens}0`, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
groups: [...acc.groups, [`0${tens}0` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
}; };
} }


lastGroup[GROUP_DIGITS_INDEX] = ( lastGroup[GROUP_DIGITS_INDEX] = (
`${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`
);
) as GroupDigits;

return { return {
...acc, ...acc,
lastToken: token, lastToken: token,


+ 6
- 6
packages/core/src/systems/en-UK/long-count/stringify.ts View File

@@ -1,7 +1,7 @@
import { import {
Group, Group,
GROUP_DIGITS_INDEX, GROUP_DIGITS_INDEX,
GROUP_PLACE_INDEX,
GROUP_PLACE_INDEX, GroupDigits,
GroupPlace, GroupPlace,
} from '../../../common'; } from '../../../common';
import { numberToExponential } from '../../../exponent'; import { numberToExponential } from '../../../exponent';
@@ -179,16 +179,16 @@ const getGroupName = (place: GroupPlace, shortenMillia: boolean) => {
const currentPlace = BigInt(Math.floor((cc.length - i - 1) / 3)); const currentPlace = BigInt(Math.floor((cc.length - i - 1) / 3));
const newGroup = [EMPTY_GROUP_DIGITS, currentPlace] as Group; const newGroup = [EMPTY_GROUP_DIGITS, currentPlace] as Group;
if (typeof firstGroup === 'undefined') { if (typeof firstGroup === 'undefined') {
newGroup[GROUP_DIGITS_INDEX] = c;
newGroup[GROUP_DIGITS_INDEX] = c as GroupDigits;
return [newGroup]; return [newGroup];
} }


if (firstGroup[0].length > 2) { if (firstGroup[0].length > 2) {
newGroup[GROUP_DIGITS_INDEX] = c;
newGroup[GROUP_DIGITS_INDEX] = c as GroupDigits;
return [newGroup, ...acc]; return [newGroup, ...acc];
} }


newGroup[GROUP_DIGITS_INDEX] = c + firstGroup[0];
newGroup[GROUP_DIGITS_INDEX] = (c + firstGroup[0]) as GroupDigits;
return [ return [
newGroup, newGroup,
...acc.slice(1), ...acc.slice(1),
@@ -309,11 +309,11 @@ export const splitIntoGroups = (value: string): Group[] => {
const lastGroupDigits = lastGroup[0].split(''); const lastGroupDigits = lastGroup[0].split('');
lastGroupDigits[currentPlaceInGroup] = c; lastGroupDigits[currentPlaceInGroup] = c;
return [...acc.slice(0, -1) ?? [], [ return [...acc.slice(0, -1) ?? [], [
lastGroupDigits.join(''),
lastGroupDigits.join('') as GroupDigits,
currentPlace, currentPlace,
]]; ]];
} }
return [...acc, [c.padEnd(3, '0'), currentPlace]];
return [...acc, [c.padEnd(3, '0') as GroupDigits, currentPlace]];
}, },
[], [],
); );


+ 13
- 10
packages/core/src/systems/en-US/short-count/parse.ts View File

@@ -2,7 +2,7 @@ import {
bigIntMax, bigIntMin, bigIntMax, bigIntMin,
Group, Group,
GROUP_DIGITS_INDEX, GROUP_DIGITS_INDEX,
GROUP_PLACE_INDEX,
GROUP_PLACE_INDEX, GroupDigits,
InvalidTokenError, InvalidTokenError,
} from '../../../common'; } from '../../../common';
import { import {
@@ -267,14 +267,14 @@ const parseThousand = (acc: ParserState, token: string): ParserState => {
if (acc.mode === ParseGroupsMode.ONES_MODE) { if (acc.mode === ParseGroupsMode.ONES_MODE) {
const ones = ONES.findIndex((o) => o === acc.lastToken); const ones = ONES.findIndex((o) => o === acc.lastToken);
if (ones > -1) { if (ones > -1) {
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}`;
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}` as GroupDigits;
} }
} else if (acc.mode === ParseGroupsMode.TENS_MODE) { } else if (acc.mode === ParseGroupsMode.TENS_MODE) {
const tens = TENS.findIndex((t) => t === acc.lastToken); const tens = TENS.findIndex((t) => t === acc.lastToken);
if (tens > -1) { if (tens > -1) {
lastGroup[GROUP_DIGITS_INDEX] = ( lastGroup[GROUP_DIGITS_INDEX] = (
`${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`
);
) as GroupDigits;
} }
} }


@@ -292,7 +292,7 @@ const parseThousand = (acc: ParserState, token: string): ParserState => {
const parseHundred = (acc: ParserState): ParserState => { const parseHundred = (acc: ParserState): ParserState => {
const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE]; const lastGroup = acc.groups.at(-1) ?? [...EMPTY_PLACE];
const hundreds = ONES.findIndex((o) => o === acc.lastToken); const hundreds = ONES.findIndex((o) => o === acc.lastToken);
lastGroup[GROUP_DIGITS_INDEX] = `${hundreds}${lastGroup[GROUP_DIGITS_INDEX].slice(1)}`;
lastGroup[GROUP_DIGITS_INDEX] = `${hundreds}${lastGroup[GROUP_DIGITS_INDEX].slice(1)}` as GroupDigits;
return { return {
...acc, ...acc,
groups: [...acc.groups.slice(0, -1), lastGroup], groups: [...acc.groups.slice(0, -1), lastGroup],
@@ -306,7 +306,7 @@ const parseFinal = (acc: ParserState): ParserState => {
if (acc.mode === ParseGroupsMode.ONES_MODE) { if (acc.mode === ParseGroupsMode.ONES_MODE) {
const ones = ONES.findIndex((o) => o === acc.lastToken); const ones = ONES.findIndex((o) => o === acc.lastToken);
if (ones > -1) { if (ones > -1) {
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}`;
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 2)}${ones}` as GroupDigits;
} }
// We assume last token without parsed place will always be the smallest // We assume last token without parsed place will always be the smallest
lastGroup[GROUP_PLACE_INDEX] = BigInt(0); lastGroup[GROUP_PLACE_INDEX] = BigInt(0);
@@ -320,7 +320,9 @@ const parseFinal = (acc: ParserState): ParserState => {
if (acc.mode === ParseGroupsMode.TENS_MODE) { if (acc.mode === ParseGroupsMode.TENS_MODE) {
const tens = TENS.findIndex((o) => o === acc.lastToken); const tens = TENS.findIndex((o) => o === acc.lastToken);
if (tens > -1) { if (tens > -1) {
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[0].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`;
lastGroup[GROUP_DIGITS_INDEX] = (
`${lastGroup[0].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`
) as GroupDigits;
} }
lastGroup[GROUP_PLACE_INDEX] = BigInt(0); lastGroup[GROUP_PLACE_INDEX] = BigInt(0);
return { return {
@@ -358,11 +360,11 @@ const parseTenPlusOnes = (acc: ParserState, token: string): ParserState => {
...acc, ...acc,
lastToken: token, lastToken: token,
mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, mode: ParseGroupsMode.TEN_PLUS_ONES_MODE,
groups: [...acc.groups, [`01${tenPlusOnes}`, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
groups: [...acc.groups, [`01${tenPlusOnes}` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
}; };
} }


lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}`;
lastGroup[GROUP_DIGITS_INDEX] = `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}1${tenPlusOnes}` as GroupDigits;
return { return {
...acc, ...acc,
lastToken: token, lastToken: token,
@@ -379,13 +381,14 @@ const parseTens = (acc: ParserState, token: string): ParserState => {
...acc, ...acc,
lastToken: token, lastToken: token,
mode: ParseGroupsMode.TENS_MODE, mode: ParseGroupsMode.TENS_MODE,
groups: [...acc.groups, [`0${tens}0`, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
groups: [...acc.groups, [`0${tens}0` as GroupDigits, lastGroup[GROUP_PLACE_INDEX] - BigInt(1)]],
}; };
} }


lastGroup[GROUP_DIGITS_INDEX] = ( lastGroup[GROUP_DIGITS_INDEX] = (
`${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}` `${lastGroup[GROUP_DIGITS_INDEX].slice(0, 1)}${tens}${lastGroup[GROUP_DIGITS_INDEX].slice(2)}`
);
) as GroupDigits;

return { return {
...acc, ...acc,
lastToken: token, lastToken: token,


+ 6
- 6
packages/core/src/systems/en-US/short-count/stringify.ts View File

@@ -1,7 +1,7 @@
import { import {
Group, Group,
GROUP_DIGITS_INDEX, GROUP_DIGITS_INDEX,
GROUP_PLACE_INDEX,
GROUP_PLACE_INDEX, GroupDigits,
GroupPlace, GroupPlace,
} from '../../../common'; } from '../../../common';
import { numberToExponential } from '../../../exponent'; import { numberToExponential } from '../../../exponent';
@@ -177,16 +177,16 @@ const getGroupName = (place: GroupPlace, shortenMillia: boolean) => {
const currentPlace = BigInt(Math.floor((cc.length - i - 1) / 3)); const currentPlace = BigInt(Math.floor((cc.length - i - 1) / 3));
const newGroup = [EMPTY_GROUP_DIGITS, currentPlace] as Group; const newGroup = [EMPTY_GROUP_DIGITS, currentPlace] as Group;
if (typeof firstGroup === 'undefined') { if (typeof firstGroup === 'undefined') {
newGroup[GROUP_DIGITS_INDEX] = c;
newGroup[GROUP_DIGITS_INDEX] = c as GroupDigits;
return [newGroup]; return [newGroup];
} }


if (firstGroup[0].length > 2) { if (firstGroup[0].length > 2) {
newGroup[GROUP_DIGITS_INDEX] = c;
newGroup[GROUP_DIGITS_INDEX] = c as GroupDigits;
return [newGroup, ...acc]; return [newGroup, ...acc];
} }


newGroup[GROUP_DIGITS_INDEX] = c + firstGroup[0];
newGroup[GROUP_DIGITS_INDEX] = (c + firstGroup[0]) as GroupDigits;
return [ return [
newGroup, newGroup,
...acc.slice(1), ...acc.slice(1),
@@ -307,11 +307,11 @@ export const splitIntoGroups = (value: string): Group[] => {
const lastGroupDigits = lastGroup[0].split(''); const lastGroupDigits = lastGroup[0].split('');
lastGroupDigits[currentPlaceInGroup] = c; lastGroupDigits[currentPlaceInGroup] = c;
return [...acc.slice(0, -1), [ return [...acc.slice(0, -1), [
lastGroupDigits.join(''),
lastGroupDigits.join('') as GroupDigits,
currentPlace, currentPlace,
]]; ]];
} }
return [...acc, [c.padEnd(3, '0'), currentPlace]];
return [...acc, [c.padEnd(3, '0') as GroupDigits, currentPlace]];
}, },
[], [],
); );


Loading…
Cancel
Save