Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to control number of fractional digits #62

Merged
merged 11 commits into from
Feb 21, 2021
48 changes: 29 additions & 19 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,6 @@ declare namespace prettyBytes {
*/
readonly locale?: boolean | string | readonly string[];

/**
[NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) international localization options.

The options `minimumFractionDigits` and `maximumFractionDigits` can be used to control the number of fractional digits displayed.

@default undefined

```
import prettyBytes = require('pretty-bytes');

prettyBytes(1900, {localeOptions: {maximumFractionDigits: 1}});
//=> '1.9 kB'

prettyBytes(1900, {localeOptions: {minimumFractionDigits: 3}});
//=> '1.900 kB'
```
*/
readonly localeOptions?: object;

/**
Format the number as [bits](https://en.wikipedia.org/wiki/Bit) instead of [bytes](https://en.wikipedia.org/wiki/Byte). This can be useful when, for example, referring to [bit rate](https://en.wikipedia.org/wiki/Bit_rate).

Expand Down Expand Up @@ -70,6 +51,35 @@ declare namespace prettyBytes {
```
*/
readonly binary?: boolean;

/**
The minimum number of fraction digits to display.
nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved

@default undefined

```
import prettyBytes = require('pretty-bytes');

nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved
prettyBytes(1900, {minimumFractionDigits: 3});
//=> '1.900 kB'
```
*/
readonly minimumFractionDigits?: number;


/**
The maximum number of fraction digits to display.

@default undefined

```
nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved
import prettyBytes = require('pretty-bytes');

prettyBytes(1900, {maximumFractionDigits: 1});
//=> '1.9 kB'
```
*/
readonly maximumFractionDigits?: number;
}
}

Expand Down
20 changes: 14 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const toLocaleString = (number, locale, options) => {
let result = number;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to just do options = {}.

Copy link
Contributor Author

@nmoinvaz nmoinvaz Jan 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I would check Object.keys(options).length > 0 in the second if statement?

if (typeof locale === 'string' || Array.isArray(locale)) {
result = number.toLocaleString(locale, options);
} else if (locale === true) {
} else if (locale === true || options !== undefined) {
result = number.toLocaleString(undefined, options);
}

Expand All @@ -70,7 +70,7 @@ module.exports = (number, options) => {
throw new TypeError(`Expected a finite number, got ${typeof number}: ${number}`);
}

options = Object.assign({bits: false, binary: false}, options);
options = Object.assign({bits: false, binary: false, minimumFractionDigits: undefined, maximumFractionDigits: undefined}, options);
nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved

const UNITS = options.bits ?
(options.binary ? BIBIT_UNITS : BIT_UNITS) :
Expand All @@ -87,22 +87,30 @@ module.exports = (number, options) => {
number = -number;
}

const locale = !options.locale && options.localeOptions ? true : options.locale;
let localeOptions;

if (options.minimumFractionDigits !== undefined) {
localeOptions = {minimumFractionDigits: options.minimumFractionDigits};
}

if (options.maximumFractionDigits !== undefined) {
localeOptions = Object.assign({maximumFractionDigits: options.maximumFractionDigits}, localeOptions);
}

if (number < 1) {
const numberString = toLocaleString(number, locale, options.localeOptions);
const numberString = toLocaleString(number, options.locale, localeOptions);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const numberString = toLocaleString(number, options.locale, localeOptions);
const numberString = toLocaleString(number, options.locale, {
...{
options.minimumFractionDigits,
options.maximumFractionDigits
}
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localeOptions should be undefined if both minimumFractionDigits and maximumFractionDigits is not set - so that it does not get localized by toLocaleString.

return prefix + numberString + ' ' + UNITS[0];
}

const exponent = Math.min(Math.floor(options.binary ? Math.log(number) / Math.log(1024) : Math.log10(number) / 3), UNITS.length - 1);
// eslint-disable-next-line unicorn/prefer-exponentiation-operator
number /= Math.pow(options.binary ? 1024 : 1000, exponent);

if (!options.localeOptions) {
if (!localeOptions) {
number = number.toPrecision(3);
}

const numberString = toLocaleString(Number(number), locale, options.localeOptions);
const numberString = toLocaleString(Number(number), options.locale, localeOptions);

const unit = UNITS[exponent];

Expand Down
27 changes: 19 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,36 @@ Default: `false` *(No localization)*

**Note:** Localization should generally work in browsers. Node.js needs to be [built](https://github.com/nodejs/node/wiki/Intl) with `full-icu` or `system-icu`. Alternatively, the [`full-icu`](https://github.com/unicode-org/full-icu-npm) module can be used to provide support at runtime. [Node.js 13](https://nodejs.org/en/blog/release/v13.0.0/) and later ships with ICU by default.

##### localeOptions
##### minimumFractionDigits

Type: `object`\
Type: `number`\
Default: `undefined`

[NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat) international localization options. The options `minimumFractionDigits` and `maximumFractionDigits` can be used to control the number of fractional digits displayed.
The minimum number of fraction digits to display.

```js
const prettyBytes = require('pretty-bytes');

// Show number with at most 1 fractional digit
prettyBytes(1900, {localeOptions: {maximumFractionDigits: 1}});
//=> '1.9 kB'

// Show number with at least 3 fractional digits
nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved
prettyBytes(1900, {localeOptions: {minimumFractionDigits: 3}});
prettyBytes(1900, {minimumFractionDigits: 3});
//=> '1.900 kB'
```

##### maximumFractionDigits

Type: `number`\
Default: `undefined`

The maximum number of fraction digits to display.

```js
const prettyBytes = require('pretty-bytes');

// Show number with at most 1 fractional digit
prettyBytes(1900, {maximumFractionDigits: 1});
//=> '1.9 kB'
```

## Related

- [pretty-bytes-cli](https://github.com/sindresorhus/pretty-bytes-cli) - CLI for this module
Expand Down
24 changes: 12 additions & 12 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,6 @@ test('locale option', t => {
}
});

test('localeOptions option', t => {
t.is(prettyBytes(1900, {localeOptions: {maximumFractionDigits: 1}}), '1.9 kB');
t.is(prettyBytes(1900, {localeOptions: {minimumFractionDigits: 3}}), '1.900 kB');
t.is(prettyBytes(1911, {localeOptions: {maximumFractionDigits: 1}}), '1.9 kB');
t.is(prettyBytes(1111, {localeOptions: {maximumFractionDigits: 2}}), '1.11 kB');
t.is(prettyBytes(1019, {localeOptions: {maximumFractionDigits: 3}}), '1.019 kB');
t.is(prettyBytes(1001, {localeOptions: {maximumFractionDigits: 3}}), '1.001 kB');
t.is(prettyBytes(4001, {localeOptions: {maximumFractionDigits: 3}, binary: true}), '3.907 kiB');
t.is(prettyBytes(18717, {localeOptions: {maximumFractionDigits: 2}, binary: true}), '18.28 kiB');
t.is(prettyBytes(18717, {localeOptions: {maximumFractionDigits: 4}, binary: true}), '18.2783 kiB');
});

test('signed option', t => {
t.is(prettyBytes(42, {signed: true}), '+42 B');
t.is(prettyBytes(-13, {signed: true}), '-13 B');
Expand Down Expand Up @@ -125,3 +113,15 @@ test('bits and binary option', t => {
t.is(prettyBytes(1025, {bits: true, binary: true}), '1 kibit');
t.is(prettyBytes(1e6, {bits: true, binary: true}), '977 kibit');
});
nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved

test('fraction digits option', t => {
t.is(prettyBytes(1900, {maximumFractionDigits: 1}), '1.9 kB');
t.is(prettyBytes(1900, {minimumFractionDigits: 3}), '1.900 kB');
t.is(prettyBytes(1911, {maximumFractionDigits: 1}), '1.9 kB');
t.is(prettyBytes(1111, {maximumFractionDigits: 2}), '1.11 kB');
t.is(prettyBytes(1019, {maximumFractionDigits: 3}), '1.019 kB');
t.is(prettyBytes(1001, {maximumFractionDigits: 3}), '1.001 kB');
t.is(prettyBytes(4001, {maximumFractionDigits: 3, binary: true}), '3.907 kiB');
t.is(prettyBytes(18717, {maximumFractionDigits: 2, binary: true}), '18.28 kiB');
t.is(prettyBytes(18717, {maximumFractionDigits: 4, binary: true}), '18.2783 kiB');
nmoinvaz marked this conversation as resolved.
Show resolved Hide resolved
});