Skip to content

Commit

Permalink
refactor(common)!: rename bigIntToStr() to decimalize() and `strT…
Browse files Browse the repository at this point in the history
…oBigInt()` to `undecimalize()`
  • Loading branch information
capt-nemo429 committed Dec 27, 2022
1 parent b22dfe2 commit 27d44f6
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 59 deletions.
91 changes: 52 additions & 39 deletions packages/common/src/utils/bigIntUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,102 @@
import { bigIntToStr, ensureBigInt, strToBigInt, sumBy } from "./bigIntUtils";
import { decimalize, ensureBigInt, sumBy, undecimalize } from "./bigIntUtils";

describe("bigIntToStr()", () => {
describe("decimalize()", () => {
it("Should decimalize", () => {
expect(bigIntToStr(1763874n)).toBe("1763874");
expect(bigIntToStr(1763874n, { decimals: 2 })).toBe("17638.74");
expect(bigIntToStr(1874n, { decimals: 10 })).toBe("0.0000001874");
expect(bigIntToStr(1n, { decimals: 2 })).toBe("0.01");
expect(bigIntToStr(1298379183n)).toBe("1298379183");
expect(decimalize(1763874n)).toBe("1763874");
expect(decimalize(1763874n, { decimals: 2 })).toBe("17638.74");
expect(decimalize(1763874n, 2)).toBe("17638.74");
expect(decimalize(1874n, { decimals: 10 })).toBe("0.0000001874");
expect(decimalize(1874n, 10)).toBe("0.0000001874");
expect(decimalize(1n, { decimals: 2 })).toBe("0.01");
expect(decimalize(1n, 2)).toBe("0.01");
expect(decimalize(1298379183n)).toBe("1298379183");
});

it("Should format", () => {
expect(
bigIntToStr(129837918300001n, {
decimalize(129837918300001n, {
decimals: 5,
thousandMark: ",",
decimalMark: "."
})
).toBe("1,298,379,183.00001");

expect(
bigIntToStr(129837918300001n, {
decimalize(129837918300001n, {
decimals: 5
})
).toBe("1298379183.00001");

expect(
bigIntToStr(129837918300001n, {
decimalize(129837918300001n, {
decimals: 5,
thousandMark: ".",
decimalMark: ","
})
).toBe("1.298.379.183,00001");

expect(
bigIntToStr(129837918300001n, {
decimalize(129837918300001n, {
decimals: 5,
thousandMark: "#",
decimalMark: "-"
})
).toBe("1#298#379#183-00001");

expect(
bigIntToStr("129837918300001", {
decimalize("129837918300001", {
decimals: 0,
thousandMark: "#"
})
).toBe("129#837#918#300#001");

expect(bigIntToStr("1100000", { decimals: 9 })).toBe("0.0011");
expect(bigIntToStr(129837918300n, { decimals: 9 })).toBe("129.8379183");
expect(bigIntToStr(100n, { decimals: 2 })).toBe("1");
expect(bigIntToStr(123n, { decimals: 2 })).toBe("1.23");
expect(bigIntToStr(1n, { decimals: 2 })).toBe("0.01");
expect(bigIntToStr(1298379183n)).toBe("1298379183");
expect(decimalize("1100000", { decimals: 9 })).toBe("0.0011");
expect(decimalize(129837918300n, { decimals: 9 })).toBe("129.8379183");
expect(decimalize(100n, { decimals: 2 })).toBe("1");
expect(decimalize(123n, { decimals: 2 })).toBe("1.23");
expect(decimalize(1n, { decimals: 2 })).toBe("0.01");
expect(decimalize(1298379183n)).toBe("1298379183");
});

it("Should do a roundtrip", () => {
const options = { decimals: 9 };
expect(bigIntToStr(strToBigInt("129.8379183", options), options)).toBe("129.8379183");
expect(decimalize(undecimalize("129.8379183", options), options)).toBe("129.8379183");
});
});

describe("strToBigInt()", () => {
describe("undecimalize()", () => {
it("Should parse BigInt strings", () => {
expect(strToBigInt(" ")).toBe(0n);
expect(strToBigInt("")).toBe(0n);
expect(strToBigInt("", { decimals: 9 })).toBe(0n);
expect(strToBigInt("0.0011", { decimals: 9 })).toBe(1100000n);
expect(strToBigInt("129.8379183", { decimals: 9 })).toBe(129837918300n);
expect(strToBigInt("1", { decimals: 2 })).toBe(100n);
expect(strToBigInt("1.23", { decimals: 2 })).toBe(123n);
expect(strToBigInt("123", { decimals: 2 })).toBe(12300n);
expect(strToBigInt("1.233", { decimals: 2 })).toBe(1233n);
expect(strToBigInt("1.23")).toBe(123n);
expect(strToBigInt("1")).toBe(1n);
expect(strToBigInt("1", { decimals: 0 })).toBe(1n);
expect(strToBigInt("0,0011", { decimals: 9, decimalMark: "," })).toBe(1100000n);
expect(strToBigInt("129-8379183", { decimals: 9, decimalMark: "-" })).toBe(129837918300n);

expect(strToBigInt("-129.8379183", { decimals: 9 })).toBe(-129837918300n);
expect(strToBigInt("-129.8379183")).toBe(-1298379183n);
expect(undecimalize(" ")).toBe(0n);
expect(undecimalize("")).toBe(0n);
expect(undecimalize("", { decimals: 9 })).toBe(0n);
expect(undecimalize("", 9)).toBe(0n);
expect(undecimalize("0.0011", { decimals: 9 })).toBe(1100000n);
expect(undecimalize("0.0011", 9)).toBe(1100000n);
expect(undecimalize("129.8379183", { decimals: 9 })).toBe(129837918300n);
expect(undecimalize("129.8379183", 9)).toBe(129837918300n);
expect(undecimalize("1", { decimals: 2 })).toBe(100n);
expect(undecimalize("1", 2)).toBe(100n);
expect(undecimalize("1.23", { decimals: 2 })).toBe(123n);
expect(undecimalize("1.23", 2)).toBe(123n);
expect(undecimalize("123", { decimals: 2 })).toBe(12300n);
expect(undecimalize("123", 2)).toBe(12300n);
expect(undecimalize("1.233", { decimals: 2 })).toBe(1233n);
expect(undecimalize("1.233", 2)).toBe(1233n);
expect(undecimalize("1.23")).toBe(123n);
expect(undecimalize("1")).toBe(1n);
expect(undecimalize("1", { decimals: 0 })).toBe(1n);
expect(undecimalize("1", 0)).toBe(1n);
expect(undecimalize("0,0011", { decimals: 9, decimalMark: "," })).toBe(1100000n);
expect(undecimalize("129-8379183", { decimals: 9, decimalMark: "-" })).toBe(129837918300n);

expect(undecimalize("-129.8379183", { decimals: 9 })).toBe(-129837918300n);
expect(undecimalize("-129.8379183", 9)).toBe(-129837918300n);
expect(undecimalize("-129.8379183")).toBe(-1298379183n);
});

it("Should throw if used with wrong number format", () => {
expect(() => {
strToBigInt("12.23.1");
undecimalize("12.23.1");
}).toThrow();
});
});
Expand All @@ -110,7 +123,7 @@ describe("BigInt sumBy()", () => {
{ key: 6, value: 659n },
{ key: 7, value: 9558n }
];
// 448317n

it("Should sum filled array", () => {
expect(sumBy(values, (x) => x.value)).toBe(461475n);
});
Expand Down
59 changes: 39 additions & 20 deletions packages/common/src/utils/bigIntUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function ensureBigInt(number: NumberLike): bigint {
return typeof number === "bigint" ? number : BigInt(number);
}

type BigIntParseOptions = {
type UndecimalizeOptions = {
/**
* Number of decimals.
*/
Expand All @@ -22,35 +22,42 @@ type BigIntParseOptions = {
decimalMark?: string;
};

export function strToBigInt(value: string, options?: BigIntParseOptions): bigint {
if (!value) {
export function undecimalize(decimalStr: string, options?: UndecimalizeOptions | number): bigint {
if (!decimalStr) {
return _0n;
}

const fragments = value.split(options?.decimalMark || ".");
options = typeof options == "number" ? { decimals: options } : options;
if (isUndefined(options)) {
options = {};
}

options.decimals = options.decimals || 0;
options.decimalMark = options.decimalMark || ".";

const fragments = decimalStr.split(options.decimalMark);
if (fragments.length > 2) {
throw new Error("Invalid numeric string.");
}

let [integer, decimal] = fragments;
integer = removeLeadingZeros(integer);
const decimals = options?.decimals || 0;
integer = _removeLeadingZeros(integer);
const negative = integer.startsWith("-") ? "-" : "";

if (!decimal) {
decimal = "0".repeat(decimals);
} else if (decimal.length < decimals) {
decimal = decimal.padEnd(decimals, "0");
decimal = "0".repeat(options.decimals);
} else if (decimal.length < options.decimals) {
decimal = decimal.padEnd(options.decimals, "0");
}

return BigInt(negative + (integer + decimal).replace(/\D/g, ""));
}

type BigIntFormatOptions = {
type FormattingOptions = {
/**
* Number of decimals.
*/
decimals?: number;
decimals: number;

/**
* Thousand mark char.
Expand All @@ -64,39 +71,51 @@ type BigIntFormatOptions = {
decimalMark?: string;
};

export function bigIntToStr(value: Amount, options?: BigIntFormatOptions): string {
export function decimalize(value: Amount, options?: FormattingOptions | number): string {
value = ensureBigInt(value);
if (!options) {
return value.toString();
}

const decimals = options.decimals || 0;
const pow = _10n ** BigInt(decimals);
options = typeof options == "number" ? { decimals: options } : options;
options.decimals = options.decimals || 0;
options.decimalMark = options.decimalMark || ".";

const pow = _10n ** BigInt(options.decimals);
const integer = value / pow;
const decimal = value - integer * pow;
const decimalPart = stripTrailingZeros(decimal.toString(10).padStart(decimals, "0"));
const integerPart = addThousandMarks(integer.toString(10), options.thousandMark);

return _buildFormattedDecimal(integer.toString(10), decimal.toString(10), options);
}

function _buildFormattedDecimal(
integer: string,
decimal: string,
options: FormattingOptions
): string {
const integerPart = _addThousandMarks(integer, options.thousandMark);
const decimalPart = _stripTrailingZeros(decimal.padStart(options.decimals, "0"));

if (decimalPart) {
return `${integerPart}${options.decimalMark || "."}${decimalPart}`;
return `${integerPart}${options.decimalMark}${decimalPart}`;
} else {
return integerPart;
}
}

function addThousandMarks(value: string, mark?: string): string {
function _addThousandMarks(value: string, mark?: string): string {
if (!mark) {
return value;
}

return value.replace(/\B(?=(\d{3})+(?!\d))/g, mark);
}

function stripTrailingZeros(value: string): string {
function _stripTrailingZeros(value: string): string {
return value.replace(/\.?0+$/, "");
}

function removeLeadingZeros(value: string): string {
function _removeLeadingZeros(value: string): string {
return value.replace(/^0+\.?/, "");
}

Expand Down

0 comments on commit 27d44f6

Please sign in to comment.