UNPKG

format-number

Version:

Formats numbers with separators every 3 digits and currency etc. Highly configurable.

257 lines (230 loc) 8.26 kB
module.exports = formatter; module.exports.default = formatter; function formatter(options) { options = options || {}; // ********************************************************************************************* // Set defaults for negatives // options.negative, options.negativeOut, options.separator retained for backward compatibility // ********************************************************************************************* // type of negative; default left options.negativeType = options.negativeType || (options.negative === 'R' ? 'right' : 'left') // negative symbols '-' or '()' if (typeof options.negativeLeftSymbol !== 'string') { switch (options.negativeType) { case 'left': options.negativeLeftSymbol = '-'; break; case 'brackets': options.negativeLeftSymbol = '('; break; default: options.negativeLeftSymbol = ''; } } if (typeof options.negativeRightSymbol !== 'string') { switch (options.negativeType) { case 'right': options.negativeRightSymbol = '-'; break; case 'brackets': options.negativeRightSymbol = ')'; break; default: options.negativeRightSymbol = ''; } } // whether negative symbol should be inside/outside prefix and suffix if (typeof options.negativeLeftOut !== "boolean") { options.negativeLeftOut = (options.negativeOut === false ? false : true); } if (typeof options.negativeRightOut !== "boolean") { options.negativeRightOut = (options.negativeOut === false ? false : true); } //prefix and suffix options.prefix = options.prefix || ''; options.suffix = options.suffix || ''; //separators if (typeof options.integerSeparator !== 'string') { options.integerSeparator = (typeof options.separator === 'string' ? options.separator : ','); } options.decimalsSeparator = typeof options.decimalsSeparator === 'string' ? options.decimalsSeparator : ''; options.decimal = options.decimal || '.'; //padders options.padLeft = options.padLeft || -1 //default no padding options.padRight = options.padRight || -1 //default no padding function format(number, overrideOptions) { overrideOptions = overrideOptions || {}; if (number || number === 0) { number = '' + number;//convert number to string if it isn't already } else { return ''; } //identify a negative number and make it absolute var output = []; var negative = number.charAt(0) === '-'; number = number.replace(/^\-/g, ''); //Prepare output with left hand negative and/or prefix if (!options.negativeLeftOut && !overrideOptions.noUnits) { output.push(options.prefix); } if (negative) { output.push(options.negativeLeftSymbol); } if (options.negativeLeftOut && !overrideOptions.noUnits) { output.push(options.prefix); } //Format core number number = number.split('.'); if (options.round != null) round(number, options.round); if (options.truncate != null) number[1] = truncate(number[1], options.truncate); if (options.padLeft > 0) number[0] = padLeft(number[0], options.padLeft); if (options.padRight > 0) number[1] = padRight(number[1], options.padRight); if (!overrideOptions.noSeparator && number[1]) number[1] = addDecimalSeparators(number[1], options.decimalsSeparator); if (!overrideOptions.noSeparator && number[0]) number[0] = addIntegerSeparators(number[0], options.integerSeparator); output.push(number[0]); if (number[1]) { output.push(options.decimal); output.push(number[1]); } //Prepare output with right hand negative and/or prefix if (options.negativeRightOut && !overrideOptions.noUnits) { output.push(options.suffix); } if (negative) { output.push(options.negativeRightSymbol); } if (!options.negativeRightOut && !overrideOptions.noUnits) { output.push(options.suffix); } //join output and return return output.join(''); } format.negative = options.negative; format.negativeOut = options.negativeOut; format.negativeType = options.negativeType; format.negativeLeftOut = options.negativeLeftOut; format.negativeLeftSymbol = options.negativeLeftSymbol; format.negativeRightOut = options.negativeRightOut; format.negativeRightSymbol = options.negativeRightSymbol; format.prefix = options.prefix; format.suffix = options.suffix; format.separate = options.separate; format.integerSeparator = options.integerSeparator; format.decimalsSeparator = options.decimalsSeparator; format.decimal = options.decimal; format.padLeft = options.padLeft; format.padRight = options.padRight; format.truncate = options.truncate; format.round = options.round; function unformat(number, allowedSeparators) { allowedSeparators = allowedSeparators || []; if (options.allowedSeparators) { options.allowedSeparators.forEach(function (s) { allowedSeparators.push (s); }); } allowedSeparators.push(options.integerSeparator); allowedSeparators.push(options.decimalsSeparator); number = number.replace(options.prefix, ''); number = number.replace(options.suffix, ''); var newNumber = number; do { number = newNumber; for (var i = 0; i < allowedSeparators.length; i++) { newNumber = newNumber.replace(allowedSeparators[i], ''); } } while (newNumber != number); return number; } format.unformat = unformat; function validate(number, allowedSeparators) { number = unformat(number, allowedSeparators); number = number.split(options.decimal); if (number.length > 2) { return false; } else if (options.truncate != null && number[1] && number[1].length > options.truncate) { return false; } else if (options.round != null && number[1] && number[1].length > options.round) { return false; } else { return /^-?\d+\.?\d*$/.test(number); } } return format; } //where x is already the integer part of the number function addIntegerSeparators(x, separator) { x += ''; if (!separator) return x; var rgx = /(\d+)(\d{3})/; while (rgx.test(x)) { x = x.replace(rgx, '$1' + separator + '$2'); } return x; } //where x is already the decimal part of the number function addDecimalSeparators(x, separator) { x += ''; if (!separator) return x; var rgx = /(\d{3})(\d+)/; while (rgx.test(x)) { x = x.replace(rgx, '$1' + separator + '$2'); } return x; } //where x is the integer part of the number function padLeft(x, padding) { x = x + ''; var buf = []; while (buf.length + x.length < padding) { buf.push('0'); } return buf.join('') + x; } //where x is the decimals part of the number function padRight(x, padding) { if (x) { x += ''; } else { x = ''; } var buf = []; while (buf.length + x.length < padding) { buf.push('0'); } return x + buf.join(''); } function truncate(x, length) { if (x) { x += ''; } if (x && x.length > length) { return x.substr(0, length); } else { return x; } } //where number is an array with 0th item as integer string and 1st item as decimal string (no negatives) function round(number, places) { if (number[1] && places >= 0 && number[1].length > places) { //truncate to correct number of decimal places var decim = number[1].slice(0, places); //if next digit was >= 5 we need to round up if (+(number[1].substr(places, 1)) >= 5) { //But first count leading zeros as converting to a number will loose them var leadingzeros = ""; while (decim.charAt(0)==="0") { leadingzeros = leadingzeros + "0"; decim = decim.substr(1); } //Then we can change decim to a number and add 1 before replacing leading zeros decim = (+decim + 1) + ''; decim = leadingzeros + decim; if (decim.length > places) { //adding one has made it longer number[0] = (+number[0]+ +decim.charAt(0)) + ''; //add value of firstchar to the integer part decim = decim.substring(1); //ignore the 1st char at the beginning which is the carry to the integer part } } number[1] = decim; } return number; }