Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@audius/fixed-decimal

Package Overview
Dependencies
Maintainers
0
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@audius/fixed-decimal - npm Package Compare versions

Comparing version 0.0.25 to 0.1.0

CHANGELOG.md

10

dist/cjs/currencies.js

@@ -9,3 +9,3 @@ "use strict";

*/
const createTokenConstructor = (decimalPlaces) => (value) => new FixedDecimal_1.FixedDecimal(value, decimalPlaces);
const createTokenConstructor = (decimalPlaces, defaultFormatOptions) => (value) => new FixedDecimal_1.FixedDecimal(value, decimalPlaces, defaultFormatOptions);
/**

@@ -42,3 +42,9 @@ * Constructs an amount of {@link AudioWei} from a fixed decimal string,

*/
exports.USDC = createTokenConstructor(6);
exports.USDC = createTokenConstructor(6, {
style: 'currency',
currency: 'USD',
currencyDisplay: 'narrowSymbol',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
//# sourceMappingURL=currencies.js.map

68

dist/cjs/FixedDecimal.js

@@ -36,3 +36,3 @@ "use strict";

*/
const defaultFormatOptions = (value) => ({
const getDefaultFormatOptions = (value) => ({
useGrouping: true,

@@ -79,2 +79,3 @@ minimumFractionDigits: 0,

decimalPlaces;
_defaultFormatOptions;
/**

@@ -91,3 +92,3 @@ * Constructs a {@link FixedDecimal}.

*/
constructor(value, decimalPlaces) {
constructor(value, decimalPlaces, defaultFormatOptions = {}) {
switch (typeof value) {

@@ -136,2 +137,6 @@ case 'number': {

}
this._defaultFormatOptions = {
...getDefaultFormatOptions(this),
...defaultFormatOptions
};
}

@@ -172,7 +177,12 @@ /**

const divisor = BigInt(10 ** digitsToRemove);
const signOffset = this.value < 0 && digitsToRemove > 0
? BigInt(-1 * 10 ** digitsToRemove)
: BigInt(0);
// Subtract one if negative w/ remainder
if (this.value < 0 && this.value % divisor !== BigInt(0)) {
return new FixedDecimal({
value: ((this.value / divisor) * divisor - divisor),
decimalPlaces: this.decimalPlaces
});
}
// Truncate otherwise
return new FixedDecimal({
value: ((this.value / divisor) * divisor + signOffset),
value: ((this.value / divisor) * divisor),
decimalPlaces: this.decimalPlaces

@@ -225,2 +235,25 @@ });

/**
* Rounds away from zero. (Opposite of trunc())
* @param decimalPlaces The number of decimal places to round to.
* @returns A new {@link FixedDecimal} with the result for chaining.
*/
expand(decimalPlaces) {
const digits = this.decimalPlaces - (decimalPlaces ?? 0);
return this._expand(digits);
}
_expand(digitsToRemove) {
if (digitsToRemove < 0) {
throw new RangeError('Digits must be non-negative');
}
const divisor = BigInt(10 ** digitsToRemove);
const remainder = this.value % divisor;
// If whole number, do nothing
if (remainder === BigInt(0)) {
return this;
}
const signMultiplier = this.value > 0 ? BigInt(1) : BigInt(-1);
// If not, truncate and add/sub 1 to the place we're rounding to
return new FixedDecimal((this.value / divisor) * divisor + divisor * signMultiplier, this.decimalPlaces);
}
/**
* Number.toPrecision() but for {@link FixedDecimal}.

@@ -264,6 +297,11 @@ * @param significantDigits The number of significant digits to keep.

toString() {
const str = this.value.toString().padStart(this.decimalPlaces + 1, '0');
return this.decimalPlaces > 0
const str = this.value
.toString()
// temp remove "-" to allow padding the decimal
.replace('-', '')
// ensure there's enough padding to include "-0.{decimal part}"
.padStart(this.decimalPlaces + 1, '0');
return `${this.value < 0 ? '-' : ''}${this.decimalPlaces > 0
? `${str.substring(0, str.length - this.decimalPlaces)}.${str.substring(str.length - this.decimalPlaces)}`
: str;
: str}`;
}

@@ -281,3 +319,3 @@ /**

const mergedOptions = {
...defaultFormatOptions(this),
...this._defaultFormatOptions,
...options

@@ -300,2 +338,5 @@ };

break;
case 'expand':
str = this.expand(mergedOptions.maximumFractionDigits).toString();
break;
}

@@ -312,5 +353,5 @@ let [whole, decimal] = str.split('.');

// Localize with a decimal to extract the separator
const wholeInt = BigInt(whole);
const wholeInt = BigInt(whole.replace('-', ''));
whole = wholeInt.toLocaleString(locale, {
...options,
...mergedOptions,
minimumFractionDigits: 0,

@@ -325,3 +366,4 @@ maximumFractionDigits: 0

})[1];
return decimal.length > 0 ? `${whole}${decimalSeparator}${decimal}` : whole;
return ((this.value < 0 ? '-' : '') +
(decimal.length > 0 ? `${whole}${decimalSeparator}${decimal}` : whole));
}

@@ -328,0 +370,0 @@ /**

@@ -6,3 +6,3 @@ import { FixedDecimal } from './FixedDecimal';

*/
const createTokenConstructor = (decimalPlaces) => (value) => new FixedDecimal(value, decimalPlaces);
const createTokenConstructor = (decimalPlaces, defaultFormatOptions) => (value) => new FixedDecimal(value, decimalPlaces, defaultFormatOptions);
/**

@@ -39,3 +39,9 @@ * Constructs an amount of {@link AudioWei} from a fixed decimal string,

*/
export const USDC = createTokenConstructor(6);
export const USDC = createTokenConstructor(6, {
style: 'currency',
currency: 'USD',
currencyDisplay: 'narrowSymbol',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
//# sourceMappingURL=currencies.js.map

@@ -33,3 +33,3 @@ /**

*/
const defaultFormatOptions = (value) => ({
const getDefaultFormatOptions = (value) => ({
useGrouping: true,

@@ -76,2 +76,3 @@ minimumFractionDigits: 0,

decimalPlaces;
_defaultFormatOptions;
/**

@@ -88,3 +89,3 @@ * Constructs a {@link FixedDecimal}.

*/
constructor(value, decimalPlaces) {
constructor(value, decimalPlaces, defaultFormatOptions = {}) {
switch (typeof value) {

@@ -133,2 +134,6 @@ case 'number': {

}
this._defaultFormatOptions = {
...getDefaultFormatOptions(this),
...defaultFormatOptions
};
}

@@ -169,7 +174,12 @@ /**

const divisor = BigInt(10 ** digitsToRemove);
const signOffset = this.value < 0 && digitsToRemove > 0
? BigInt(-1 * 10 ** digitsToRemove)
: BigInt(0);
// Subtract one if negative w/ remainder
if (this.value < 0 && this.value % divisor !== BigInt(0)) {
return new FixedDecimal({
value: ((this.value / divisor) * divisor - divisor),
decimalPlaces: this.decimalPlaces
});
}
// Truncate otherwise
return new FixedDecimal({
value: ((this.value / divisor) * divisor + signOffset),
value: ((this.value / divisor) * divisor),
decimalPlaces: this.decimalPlaces

@@ -222,2 +232,25 @@ });

/**
* Rounds away from zero. (Opposite of trunc())
* @param decimalPlaces The number of decimal places to round to.
* @returns A new {@link FixedDecimal} with the result for chaining.
*/
expand(decimalPlaces) {
const digits = this.decimalPlaces - (decimalPlaces ?? 0);
return this._expand(digits);
}
_expand(digitsToRemove) {
if (digitsToRemove < 0) {
throw new RangeError('Digits must be non-negative');
}
const divisor = BigInt(10 ** digitsToRemove);
const remainder = this.value % divisor;
// If whole number, do nothing
if (remainder === BigInt(0)) {
return this;
}
const signMultiplier = this.value > 0 ? BigInt(1) : BigInt(-1);
// If not, truncate and add/sub 1 to the place we're rounding to
return new FixedDecimal((this.value / divisor) * divisor + divisor * signMultiplier, this.decimalPlaces);
}
/**
* Number.toPrecision() but for {@link FixedDecimal}.

@@ -261,6 +294,11 @@ * @param significantDigits The number of significant digits to keep.

toString() {
const str = this.value.toString().padStart(this.decimalPlaces + 1, '0');
return this.decimalPlaces > 0
const str = this.value
.toString()
// temp remove "-" to allow padding the decimal
.replace('-', '')
// ensure there's enough padding to include "-0.{decimal part}"
.padStart(this.decimalPlaces + 1, '0');
return `${this.value < 0 ? '-' : ''}${this.decimalPlaces > 0
? `${str.substring(0, str.length - this.decimalPlaces)}.${str.substring(str.length - this.decimalPlaces)}`
: str;
: str}`;
}

@@ -278,3 +316,3 @@ /**

const mergedOptions = {
...defaultFormatOptions(this),
...this._defaultFormatOptions,
...options

@@ -297,2 +335,5 @@ };

break;
case 'expand':
str = this.expand(mergedOptions.maximumFractionDigits).toString();
break;
}

@@ -309,5 +350,5 @@ let [whole, decimal] = str.split('.');

// Localize with a decimal to extract the separator
const wholeInt = BigInt(whole);
const wholeInt = BigInt(whole.replace('-', ''));
whole = wholeInt.toLocaleString(locale, {
...options,
...mergedOptions,
minimumFractionDigits: 0,

@@ -322,3 +363,4 @@ maximumFractionDigits: 0

})[1];
return decimal.length > 0 ? `${whole}${decimalSeparator}${decimal}` : whole;
return ((this.value < 0 ? '-' : '') +
(decimal.length > 0 ? `${whole}${decimalSeparator}${decimal}` : whole));
}

@@ -325,0 +367,0 @@ /**

@@ -14,3 +14,3 @@ import type BN from 'bn.js';

*/
type FixedDecimalFormatOptions = {
type FixedDecimalFormatOptions = Omit<BigIntToLocaleStringOptions, 'minimumFractionDigits' | 'maximumFractionDigits'> & {
/**

@@ -55,7 +55,12 @@ * Whether to use grouping separators, such as thousands separators or thousand/lakh/crore separators.

*
* Note: Does not support `'expand'`, `'halfCeil'`, `'halfFloor'`,
* `'halfTrunc'` or `'halfEven'`
* `'expand'`
* > round away from 0. The magnitude of the value is always increased by
* rounding. Positive values round up.
* Negative values round "more negative".
*
* Note: Does not support `'halfCeil'`, `'halfFloor'`, `'halfTrunc'`
* or `'halfEven'`
* @defaultValue `'trunc'`
*/
roundingMode?: 'ceil' | 'floor' | 'trunc' | 'halfExpand';
roundingMode?: 'ceil' | 'floor' | 'trunc' | 'halfExpand' | 'expand';
/**

@@ -113,2 +118,3 @@ * The strategy for displaying trailing zeros on whole numbers.

decimalPlaces: number;
private _defaultFormatOptions;
/**

@@ -125,3 +131,3 @@ * Constructs a {@link FixedDecimal}.

*/
constructor(value: FixedDecimalCtorArgs<bigint> | BigIntBrand | NoBrand<bigint> | number | string | BNBrand | NoBrand<BN>, decimalPlaces?: number);
constructor(value: FixedDecimalCtorArgs<bigint> | BigIntBrand | NoBrand<bigint> | number | string | BNBrand | NoBrand<BN>, decimalPlaces?: number, defaultFormatOptions?: FixedDecimalFormatOptions);
/**

@@ -156,2 +162,9 @@ * Math.ceil() but for {@link FixedDecimal}.

/**
* Rounds away from zero. (Opposite of trunc())
* @param decimalPlaces The number of decimal places to round to.
* @returns A new {@link FixedDecimal} with the result for chaining.
*/
expand(decimalPlaces?: number): FixedDecimal<BigIntBrand, BNBrand>;
private _expand;
/**
* Number.toPrecision() but for {@link FixedDecimal}.

@@ -158,0 +171,0 @@ * @param significantDigits The number of significant digits to keep.

{
"name": "@audius/fixed-decimal",
"version": "0.0.25",
"version": "0.1.0",
"description": "A data structure to represent fixed precision decimals",

@@ -33,5 +33,5 @@ "main": "dist/cjs/index.js",

"bn.js": "5.1.0",
"eslint": "8.19.0",
"eslint": "8.56.0",
"vitest": "0.34.6"
}
}

@@ -65,2 +65,7 @@ import BN from 'bn.js'

})
it('defaults to two decimals', function () {
expect(USDC(1.234567).toLocaleString()).toBe('$1.23')
expect(USDC(-1.234567).toLocaleString()).toBe('-$1.23')
})
})

@@ -12,6 +12,7 @@ import type BN from 'bn.js'

<T extends bigint, K extends BN = BN>(
decimalPlaces: ConstructorParameters<typeof FixedDecimal<T, K>>[1]
decimalPlaces: ConstructorParameters<typeof FixedDecimal<T, K>>[1],
defaultFormatOptions?: ConstructorParameters<typeof FixedDecimal<T, K>>[2]
) =>
(value: ConstructorParameters<typeof FixedDecimal<T, K>>[0]) =>
new FixedDecimal<T, K>(value, decimalPlaces)
new FixedDecimal<T, K>(value, decimalPlaces, defaultFormatOptions)

@@ -87,2 +88,8 @@ /**

*/
export const USDC = createTokenConstructor<UsdcWei, BNUSDC>(6)
export const USDC = createTokenConstructor<UsdcWei, BNUSDC>(6, {
style: 'currency',
currency: 'USD',
currencyDisplay: 'narrowSymbol',
minimumFractionDigits: 2,
maximumFractionDigits: 2
})

@@ -133,2 +133,8 @@ import { BN } from 'bn.js'

it('floors no-op correctly', function () {
expect(new FixedDecimal(BigInt(-100000), 6).floor(2).toString()).toBe(
'-0.100000'
)
})
it('floors large numbers correctly', function () {

@@ -343,2 +349,56 @@ expect(

describe('expand', function () {
it('expands positive decimals correctly', function () {
expect(new FixedDecimal(1.2345).expand().toString()).toBe('2.0000')
})
it('expands negative decimals correctly', function () {
expect(new FixedDecimal(-1.2345).expand().toString()).toBe('-2.0000')
})
it('expands 0 correctly', function () {
expect(new FixedDecimal(0, 3).expand().toString()).toBe('0.000')
})
it('expands whole numbers correctly', function () {
expect(new FixedDecimal(4, 3).expand().toString()).toBe('4.000')
})
it('expands large numbers correctly', function () {
expect(
new FixedDecimal(BigInt('1234567890123456789099999999999999999999'), 20)
.expand()
.toString()
).toBe('12345678901234567891.00000000000000000000')
})
it('expands tiny numbers correctly', function () {
expect(new FixedDecimal(BigInt('1'), 20).expand().toString()).toBe(
'1.00000000000000000000'
)
})
it('expands to arbitrary decimal places correctly', function () {
expect(
new FixedDecimal(BigInt('1234567890123456789099999999999999999999'), 20)
.expand(2)
.toString()
).toBe('12345678901234567891.00000000000000000000')
})
it('throws when decimal places are out of range', function () {
expect(() =>
new FixedDecimal(BigInt('1234567890123456789099999999999999999999'), 20)
.expand(50)
.toString()
).toThrow('Digits must be non-negative')
})
it('expands to 1s place of represented place if decimal places is beyond number', function () {
expect(new FixedDecimal(BigInt('12345'), 3).expand(-10).toString()).toBe(
'10000000000.000'
)
})
})
describe('toPrecision', function () {

@@ -615,3 +675,7 @@ it('work on positive numbers', function () {

})
it('handles fractional negatives correctly', function () {
expect(new FixedDecimal('-0.123').toLocaleString('en-US')).toBe('-0.123')
})
})
})

@@ -41,3 +41,6 @@ import type BN from 'bn.js'

*/
type FixedDecimalFormatOptions = {
type FixedDecimalFormatOptions = Omit<
BigIntToLocaleStringOptions,
'minimumFractionDigits' | 'maximumFractionDigits'
> & {
/**

@@ -82,7 +85,12 @@ * Whether to use grouping separators, such as thousands separators or thousand/lakh/crore separators.

*
* Note: Does not support `'expand'`, `'halfCeil'`, `'halfFloor'`,
* `'halfTrunc'` or `'halfEven'`
* `'expand'`
* > round away from 0. The magnitude of the value is always increased by
* rounding. Positive values round up.
* Negative values round "more negative".
*
* Note: Does not support `'halfCeil'`, `'halfFloor'`, `'halfTrunc'`
* or `'halfEven'`
* @defaultValue `'trunc'`
*/
roundingMode?: 'ceil' | 'floor' | 'trunc' | 'halfExpand'
roundingMode?: 'ceil' | 'floor' | 'trunc' | 'halfExpand' | 'expand'
/**

@@ -118,3 +126,3 @@ * The strategy for displaying trailing zeros on whole numbers.

*/
const defaultFormatOptions = (value: FixedDecimal) =>
const getDefaultFormatOptions = (value: FixedDecimal) =>
({

@@ -166,2 +174,3 @@ useGrouping: true,

public decimalPlaces: number
private _defaultFormatOptions: FixedDecimalFormatOptions

@@ -188,3 +197,4 @@ /**

| NoBrand<BN>,
decimalPlaces?: number
decimalPlaces?: number,
defaultFormatOptions: FixedDecimalFormatOptions = {}
) {

@@ -241,2 +251,6 @@ switch (typeof value) {

}
this._defaultFormatOptions = {
...getDefaultFormatOptions(this),
...defaultFormatOptions
}
}

@@ -281,8 +295,12 @@

const divisor = BigInt(10 ** digitsToRemove)
const signOffset =
this.value < 0 && digitsToRemove > 0
? BigInt(-1 * 10 ** digitsToRemove)
: BigInt(0)
// Subtract one if negative w/ remainder
if (this.value < 0 && this.value % divisor !== BigInt(0)) {
return new FixedDecimal<BigIntBrand, BNBrand>({
value: ((this.value / divisor) * divisor - divisor) as BigIntBrand,
decimalPlaces: this.decimalPlaces
})
}
// Truncate otherwise
return new FixedDecimal<BigIntBrand, BNBrand>({
value: ((this.value / divisor) * divisor + signOffset) as BigIntBrand,
value: ((this.value / divisor) * divisor) as BigIntBrand,
decimalPlaces: this.decimalPlaces

@@ -343,2 +361,30 @@ })

/**
* Rounds away from zero. (Opposite of trunc())
* @param decimalPlaces The number of decimal places to round to.
* @returns A new {@link FixedDecimal} with the result for chaining.
*/
public expand(decimalPlaces?: number) {
const digits = this.decimalPlaces - (decimalPlaces ?? 0)
return this._expand(digits)
}
private _expand(digitsToRemove: number) {
if (digitsToRemove < 0) {
throw new RangeError('Digits must be non-negative')
}
const divisor = BigInt(10 ** digitsToRemove)
const remainder = this.value % divisor
// If whole number, do nothing
if (remainder === BigInt(0)) {
return this
}
const signMultiplier = this.value > 0 ? BigInt(1) : BigInt(-1)
// If not, truncate and add/sub 1 to the place we're rounding to
return new FixedDecimal<BigIntBrand, BNBrand>(
(this.value / divisor) * divisor + divisor * signMultiplier,
this.decimalPlaces
)
}
/**
* Number.toPrecision() but for {@link FixedDecimal}.

@@ -389,8 +435,15 @@ * @param significantDigits The number of significant digits to keep.

public toString() {
const str = this.value.toString().padStart(this.decimalPlaces + 1, '0')
return this.decimalPlaces > 0
? `${str.substring(0, str.length - this.decimalPlaces)}.${str.substring(
str.length - this.decimalPlaces
)}`
: str
const str = this.value
.toString()
// temp remove "-" to allow padding the decimal
.replace('-', '')
// ensure there's enough padding to include "-0.{decimal part}"
.padStart(this.decimalPlaces + 1, '0')
return `${this.value < 0 ? '-' : ''}${
this.decimalPlaces > 0
? `${str.substring(0, str.length - this.decimalPlaces)}.${str.substring(
str.length - this.decimalPlaces
)}`
: str
}`
}

@@ -409,3 +462,3 @@

const mergedOptions = {
...defaultFormatOptions(this),
...this._defaultFormatOptions,
...options

@@ -428,2 +481,5 @@ }

break
case 'expand':
str = this.expand(mergedOptions.maximumFractionDigits).toString()
break
}

@@ -446,5 +502,5 @@

// Localize with a decimal to extract the separator
const wholeInt = BigInt(whole)
const wholeInt = BigInt(whole.replace('-', ''))
whole = wholeInt.toLocaleString(locale, {
...options,
...mergedOptions,
minimumFractionDigits: 0,

@@ -461,3 +517,6 @@ maximumFractionDigits: 0

return decimal.length > 0 ? `${whole}${decimalSeparator}${decimal}` : whole
return (
(this.value < 0 ? '-' : '') +
(decimal.length > 0 ? `${whole}${decimalSeparator}${decimal}` : whole)
)
}

@@ -464,0 +523,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc