|
- import Big from 'big.js'
- import ConverterStream from './ConverterStream'
- import { ReadStreamOptions, ConvertOptions, NumberSystem, Digit } from './common'
-
- export default class Converter {
- constructor(private readonly system: NumberSystem, private options: ConvertOptions) {}
-
- private convertString = (value: string): string => {
- let converted: string[] = []
- try {
- const big = new Big(value)
- const { e: exponent, c: coefficients } = big
- const isExponentSmall = exponent < 1000
- if (isExponentSmall) {
- return this.convert(BigInt(big.toFixed()))
- }
- let currentPlace = exponent % 3
- let thousandPower = BigInt(exponent) / 3n
- coefficients.reduce(
- ([place, hundredsRaw = 0, tensRaw = 0, onesRaw = 0], c) => {
- let thePlace = (place + 3) % 3
- const nextPlace = (place + 3 - 1) % 3
-
- switch (thePlace) {
- case 2:
- return [nextPlace, c, tensRaw, onesRaw]
- case 1:
- return [nextPlace, hundredsRaw, c, onesRaw]
- default:
- case 0:
- break
- }
-
- let kiloName: string | undefined
- let kiloCount: string
- const hundreds = hundredsRaw as Digit
- const tens = tensRaw as Digit
- const ones = c as Digit
- if (!(ones === 0 && tens === 0 && hundreds === 0)) {
- if (thousandPower > 0n) {
- const { scale = 'short' } = this.options
- kiloName = this.system.getKiloName[scale!]!(thousandPower)
- }
- kiloCount = this.system.getKiloCount(hundreds, tens, ones)
- converted.push(this.system.joinKilo(kiloCount, kiloName))
- }
- thousandPower = thousandPower - 1n
- return [nextPlace, 0, 0, 0]
- },
- [currentPlace],
- )
- } catch {}
- return converted.join(' ')
- }
-
- private convertBigInt = (value: bigint): string => {
- let converted: string[] = []
- let current = value as bigint
- let thousandPower = 0n
- while (current > 0n) {
- const hundreds = Number(((current % 1000n) / 100n) % 10n) as Digit
- const tens = Number(((current % 100n) / 10n) % 10n) as Digit
- const ones = Number(current % 10n) as Digit
-
- let kiloName: string | undefined
- let kiloCount: string
- if (!(ones === 0 && tens === 0 && hundreds === 0)) {
- if (thousandPower > 0n) {
- const { scale = 'short' } = this.options
- kiloName = this.system.getKiloName[scale!]!(thousandPower)
- }
- kiloCount = this.system.getKiloCount(hundreds, tens, ones)
- converted.unshift(this.system.joinKilo(kiloCount, kiloName))
- }
-
- thousandPower = thousandPower + 1n
- current = current / 1000n
- }
- return converted.join(' ')
- }
-
- public convert = (value: string | number | bigint): string => {
- switch (typeof value!) {
- case 'string':
- return this.convertString(value as string)
- case 'number':
- return this.convertString(value.toString(10))
- case 'bigint':
- return this.convertBigInt(value as bigint)
- default:
- break
- }
- throw TypeError('Invalid argument passed to value.')
- }
-
- public readStream = (streamOptions: ReadStreamOptions): ConverterStream => {
- return new ConverterStream(this.convert, streamOptions)
- }
- }
|