Source: units.js

/*!
 * Module Units
 */

/**
 * @namespace Units
 */

const MODULE_NAME = 'Units';



//###[ IMPORTS ]########################################################################################################

import {orDefault, assert, isNaN, isArray, round} from './basic.js';



//###[ DATA ]###########################################################################################################

export const
	LOCAL_FLOAT_SEPARATOR = (0.1).toLocaleString().replace(/[0-9]/g, '').slice(0, 1),
	LOCAL_THOUSAND_SEPARATOR = (1000).toLocaleString().replace(/[0-9]/g, '').slice(0, 1)
;



//###[ EXPORTS ]########################################################################################################

/**
 * @namespace Units:asFileSize
 */

/**
 * Renders a byte number as a human-readable file size with the correct unit.
 *
 * Switch calculation base by setting useBinaryBase to true.
 * Today, file sizes are usually calculated against a decimal base of 1000, while in the
 * past, a binary base of 1024 was commonly used (and still is today by some software such as Microsoft Windows).
 * In 1998 the IEC standardized byte units to be metric in nature, which is the base assumption of this method.
 *
 * @param {Number} bytes - file size in bytes to render as string
 * @param {?String} [separator=LOCAL_FLOAT_SEPARATOR] - the character to separate the fraction in float numbers, will default to the current browser's default for local strings
 * @param {?Number} [precision=1] - the floating point precision to use for the size
 * @param {?Boolean} [useBinaryBase=false] - set to true to activate binary calculation and units
 * @returns {String} the formatted file size
 *
 * @memberof Units:asFileSize
 * @alias asFileSize
 * @see https://en.wikipedia.org/wiki/Kilobyte
 * @example
 * asFileSize(1_500_000, ',')
 * => '1,5 MB'
 * asFileSize(1024, '.', 0, true)
 * => '1 KiB'
 */
export function asFileSize(bytes, separator=LOCAL_FLOAT_SEPARATOR, precision=1, useBinaryBase=false){
	const __methodName__ = 'asFileSize';

	bytes = parseInt(bytes, 10);
	assert(
		!isNaN(bytes) && (bytes >= 0),
		`${MODULE_NAME}:${__methodName__} | bytes not usable or negative`
	);

	separator = orDefault(separator, LOCAL_FLOAT_SEPARATOR, 'str');
	precision = orDefault(precision, 1, 'int');

	const
		thresh = !!useBinaryBase ? 1024 : 1000,
		units = !!useBinaryBase
			? ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']
			: ['kB','MB','GB','TB','PB','EB','ZB','YB']
	;

	if( bytes < thresh ){
		return `${bytes} B`;
	}

	let unitIndex = -1;
	do {
		bytes /= thresh;
		unitIndex++;
	} while(
		(bytes >= thresh)
		&& (unitIndex < (units.length - 1))
	);

	bytes = `${round(bytes, precision)}`.replace('.', separator);
	return `${bytes} ${units[unitIndex]}`;
}



/**
 * @namespace Units:asCurrency
 */

/**
 * Renders a number as a currency value, using native Intl.NumberFormat functionality.
 *
 * @param {Number} number - the number to use as a currency amount
 * @param {?String|Array<String>} [locale='en-US'] - locale to use, use array to define fallback; always falls back to en-US if nothing else works
 * @param {?String} [currency='USD'] - a ISO4217 currency code, such as EUR for Euro
 * @param {?String} [currencyDisplay='symbol'] - one of "symbol", "narrowSymbol", "code" or "name", defining, how the currency should be displayed in the result
 * @returns {String} the formatted currency amount
 *
 * @memberof Units:asCurrency
 * @alias asCurrency
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
 * @see https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes
 * @example
 * asCurrency(42.666)
 * => '42.67 $'
 * asCurrency(42.666, 'de-DE', 'EUR')
 * => '42,67 €'
 */
export function asCurrency(number, locale='en-US', currency='USD', currencyDisplay='symbol'){
	number = parseFloat(number);

	locale = orDefault(locale, 'en-US');
	if(
		(!isArray(locale) && (locale !== 'en-US'))
		|| (isArray(locale) && !locale.includes('en-US'))
	){
		locale = [].concat(locale).concat('en-US');
	}

	currency = orDefault(currency, 'USD', 'str');
	currencyDisplay = orDefault(currencyDisplay, 'symbol', 'str');

	return new Intl.NumberFormat(
		locale,
		{
			style : 'currency',
			currency,
			currencyDisplay,
		}
	).format(number);
}



/**
 * @namespace Units:asDecimal
 */

/**
 * Renders a number as a decimal value, using native Intl.NumberFormat functionality.
 *
 * @param {Number} number - the number to use as a decimal amount
 * @param {?String|Array<String>} [locale='en-US'] - locale to use, use array to define fallback; always falls back to en-US if nothing else works
 * @param {?Number} [minPrecision=2] - the minimal precision to use in decimal display
 * @param {?Number} [maxPrecision=null] - the minimal precision to use in decimal display; if nullish, will be set to minPrecision
 * @returns {String} the formatted decimal amount
 *
 * @memberof Units:asDecimal
 * @alias asDecimal
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
 * @example
 * asDecimal(42.666)
 * => '42.67'
 * asDecimal(42.666, 'de-DE', 1)
 * => '42,7'
 */
export function asDecimal(number, locale='en-US', minPrecision=2, maxPrecision=null){
	number = parseFloat(number);

	locale = orDefault(locale, 'en-US');
	if(
		(!isArray(locale) && (locale !== 'en-US'))
		|| (isArray(locale) && !locale.includes('en-US'))
	){
		locale = [].concat(locale).concat('en-US');
	}

	minPrecision = orDefault(minPrecision, 2, 'int');
	maxPrecision = orDefault(maxPrecision, minPrecision, 'int');

	return new Intl.NumberFormat(
		locale,
		{
			style : 'decimal',
			useGrouping : false,
			minimumFractionDigits : minPrecision,
			maximumFractionDigits : maxPrecision
		}
	).format(number);
}