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
41 changes: 41 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,47 @@ declare namespace prettyBytes {
```
*/
readonly binary?: boolean;

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

If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.

@default undefined

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

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

prettyBytes(1900);
//=> '1.9 kB'
```
*/
readonly minimumFractionDigits?: number;


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

If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.

@default undefined

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

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

prettyBytes(1920);
//=> '1.92 kB'
```
*/
readonly maximumFractionDigits?: number;
}
}

Expand Down
29 changes: 22 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ Formats the given number using `Number#toLocaleString`.
- If locale is true, the system default locale is used for translation.
- If no value for locale is specified, the number is returned unmodified.
*/
const toLocaleString = (number, locale) => {
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);
} else if (locale === true) {
result = number.toLocaleString();
result = number.toLocaleString(locale, options);
} else if (locale === true || options !== undefined) {
result = number.toLocaleString(undefined, options);
}

return result;
Expand Down Expand Up @@ -87,15 +87,30 @@ module.exports = (number, options) => {
number = -number;
}

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, options.locale);
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 = Number((number / Math.pow(options.binary ? 1024 : 1000, exponent)).toPrecision(3));
const numberString = toLocaleString(number, options.locale);
number /= Math.pow(options.binary ? 1024 : 1000, exponent);

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

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

const unit = UNITS[exponent];

Expand Down
40 changes: 40 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,46 @@ 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.

##### minimumFractionDigits

Type: `number`\
Default: `undefined`

The minimum number of fraction digits to display.

If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.

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

// Show the number with at least 3 fractional digits
prettyBytes(1900, {minimumFractionDigits: 3});
//=> '1.900 kB'

prettyBytes(1900);
//=> '1.9 kB'
```

##### maximumFractionDigits

Type: `number`\
Default: `undefined`

The maximum number of fraction digits to display.

If neither `minimumFractionDigits` or `maximumFractionDigits` are set, the default behavior is to round to 3 significant digits.

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

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

prettyBytes(1920);
//=> '1.92 kB'
```

## Related

- [pretty-bytes-cli](https://github.com/sindresorhus/pretty-bytes-cli) - CLI for this module
Expand Down
16 changes: 16 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,19 @@ 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('fractional digits options', 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(1000, {minimumFractionDigits: 1, maximumFractionDigits: 3}), '1.0 kB');
t.is(prettyBytes(3942, {minimumFractionDigits: 1, maximumFractionDigits: 2}), '3.94 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
t.is(prettyBytes(32768, {minimumFractionDigits: 2, maximumFractionDigits: 3, binary: true}), '32.00 kiB');
t.is(prettyBytes(65536, {minimumFractionDigits: 1, maximumFractionDigits: 3, binary: true}), '64.0 kiB');
});