1(function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 3 typeof define === 'function' && define.amd ? define(['exports'], factory) : 4 (factory((global.accounting = global.accounting || {}))); 5}(this, function (exports) { 'use strict'; 6 7 function __commonjs(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } 8 9 /** 10 * The library's settings configuration object. 11 * 12 * Contains default parameters for currency and number formatting 13 */ 14 var settings = { 15 symbol: '$', // default currency symbol is '$' 16 format: '%s%v', // controls output: %s = symbol, %v = value (can be object, see docs) 17 decimal: '.', // decimal point separator 18 thousand: ',', // thousands separator 19 precision: 2, // decimal places 20 grouping: 3, // digit grouping (not implemented yet) 21 stripZeros: false, // strip insignificant zeros from decimal part 22 fallback: 0 // value returned on unformat() failure 23 }; 24 25 /** 26 * Takes a string/array of strings, removes all formatting/cruft and returns the raw float value 27 * Alias: `accounting.parse(string)` 28 * 29 * Decimal must be included in the regular expression to match floats (defaults to 30 * accounting.settings.decimal), so if the number uses a non-standard decimal 31 * separator, provide it as the second argument. 32 * 33 * Also matches bracketed negatives (eg. '$ (1.99)' => -1.99) 34 * 35 * Doesn't throw any errors (`NaN`s become 0) but this may change in future 36 * 37 * ```js 38 * accounting.unformat("£ 12,345,678.90 GBP"); // 12345678.9 39 * ``` 40 * 41 * @method unformat 42 * @for accounting 43 * @param {String|Array<String>} value The string or array of strings containing the number/s to parse. 44 * @param {Number} decimal Number of decimal digits of the resultant number 45 * @return {Float} The parsed number 46 */ 47 function unformat(value) { 48 var decimal = arguments.length <= 1 || arguments[1] === undefined ? settings.decimal : arguments[1]; 49 var fallback = arguments.length <= 2 || arguments[2] === undefined ? settings.fallback : arguments[2]; 50 51 // Recursively unformat arrays: 52 if (Array.isArray(value)) { 53 return value.map(function (val) { 54 return unformat(val, decimal, fallback); 55 }); 56 } 57 58 // Return the value as-is if it's already a number: 59 if (typeof value === 'number') return value; 60 61 // Build regex to strip out everything except digits, decimal point and minus sign: 62 var regex = new RegExp('[^0-9-(-)-' + decimal + ']', ['g']); 63 var unformattedValueString = ('' + value).replace(regex, '') // strip out any cruft 64 .replace(decimal, '.') // make sure decimal point is standard 65 .replace(/\(([-]*\d*[^)]?\d+)\)/g, '-$1') // replace bracketed values with negatives 66 .replace(/\((.*)\)/, ''); // remove any brackets that do not have numeric value 67 68 /** 69 * Handling -ve number and bracket, eg. 70 * (-100) = 100, -(100) = 100, --100 = 100 71 */ 72 var negative = (unformattedValueString.match(/-/g) || 2).length % 2, 73 absUnformatted = parseFloat(unformattedValueString.replace(/-/g, '')), 74 unformatted = absUnformatted * (negative ? -1 : 1); 75 76 // This will fail silently which may cause trouble, let's wait and see: 77 return !isNaN(unformatted) ? unformatted : fallback; 78 } 79 80 /** 81 * Check and normalise the value of precision (must be positive integer) 82 */ 83 function _checkPrecision(val, base) { 84 val = Math.round(Math.abs(val)); 85 return isNaN(val) ? base : val; 86 } 87 88 /** 89 * Implementation of toFixed() that treats floats more like decimals 90 * 91 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present 92 * problems for accounting- and finance-related software. 93 * 94 * ```js 95 * (0.615).toFixed(2); // "0.61" (native toFixed has rounding issues) 96 * accounting.toFixed(0.615, 2); // "0.62" 97 * ``` 98 * 99 * @method toFixed 100 * @for accounting 101 * @param {Float} value The float to be treated as a decimal number. 102 * @param {Number} [precision=2] The number of decimal digits to keep. 103 * @return {String} The given number transformed into a string with the given precission 104 */ 105 function toFixed(value, precision) { 106 precision = _checkPrecision(precision, settings.precision); 107 var power = Math.pow(10, precision); 108 109 // Multiply up by precision, round accurately, then divide and use native toFixed(): 110 return (Math.round((value + 1e-8) * power) / power).toFixed(precision); 111 } 112 113 var index = __commonjs(function (module) { 114 /* eslint-disable no-unused-vars */ 115 'use strict'; 116 var hasOwnProperty = Object.prototype.hasOwnProperty; 117 var propIsEnumerable = Object.prototype.propertyIsEnumerable; 118 119 function toObject(val) { 120 if (val === null || val === undefined) { 121 throw new TypeError('Object.assign cannot be called with null or undefined'); 122 } 123 124 return Object(val); 125 } 126 127 module.exports = Object.assign || function (target, source) { 128 var from; 129 var to = toObject(target); 130 var symbols; 131 132 for (var s = 1; s < arguments.length; s++) { 133 from = Object(arguments[s]); 134 135 for (var key in from) { 136 if (hasOwnProperty.call(from, key)) { 137 to[key] = from[key]; 138 } 139 } 140 141 if (Object.getOwnPropertySymbols) { 142 symbols = Object.getOwnPropertySymbols(from); 143 for (var i = 0; i < symbols.length; i++) { 144 if (propIsEnumerable.call(from, symbols[i])) { 145 to[symbols[i]] = from[symbols[i]]; 146 } 147 } 148 } 149 } 150 151 return to; 152 }; 153 }); 154 155 var objectAssign = (index && typeof index === 'object' && 'default' in index ? index['default'] : index); 156 157 function _stripInsignificantZeros(str, decimal) { 158 var parts = str.split(decimal); 159 var integerPart = parts[0]; 160 var decimalPart = parts[1].replace(/0+$/, ''); 161 162 if (decimalPart.length > 0) { 163 return integerPart + decimal + decimalPart; 164 } 165 166 return integerPart; 167 } 168 169 /**
170 * Format a number, with comma-separated thousands and custom precision/decimal places 171 * Alias: `accounting.format()` 172 * 173 * Localise by overriding the precision and thousand / decimal separators 174 * 175 * ```js 176 * accounting.formatNumber(5318008); // 5,318,008 177 * accounting.formatNumber(9876543.21, { precision: 3, thousand: " " }); // 9 876 543.210 178 * ``` 179 * 180 * @method formatNumber 181 * @for accounting 182 * @param {Number} number The number to be formatted. 183 * @param {Object} [opts={}] Object containing all the options of the method. 184 * @return {String} The given number properly formatted. 185 */ 186 function formatNumber(number) { 187 var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 188 189 // Resursively format arrays: 190 if (Array.isArray(number)) { 191 return number.map(function (val) { 192 return formatNumber(val, opts); 193 }); 194 } 195 196 // Build options object from second param (if object) or all params, extending defaults: 197 opts = objectAssign({}, settings, opts); 198 199 // Do some calc: 200 var negative = number < 0 ? '-' : ''; 201 var base = parseInt(toFixed(Math.abs(number), opts.precision), 10) + ''; 202 var mod = base.length > 3 ? base.length % 3 : 0; 203 204 // Format the number: 205 var formatted = negative + (mod ? base.substr(0, mod) + opts.thousand : '') + base.substr(mod).replace(/(\d{3})(?=\d)/g, '$1' + opts.thousand) + (opts.precision > 0 ? opts.decimal + toFixed(Math.abs(number), opts.precision).split('.')[1] : ''); 206 207 return opts.stripZeros ? _stripInsignificantZeros(formatted, opts.decimal) : formatted; 208 } 209 210 var index$1 = __commonjs(function (module) { 211 'use strict'; 212 213 var strValue = String.prototype.valueOf; 214 var tryStringObject = function tryStringObject(value) { 215 try { 216 strValue.call(value); 217 return true; 218 } catch (e) { 219 return false; 220 } 221 }; 222 var toStr = Object.prototype.toString; 223 var strClass = '[object String]'; 224 var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; 225 226 module.exports = function isString(value) { 227 if (typeof value === 'string') { return true; } 228 if (typeof value !== 'object') { return false; } 229 return hasToStringTag ? tryStringObject(value) : toStr.call(value) === strClass; 230 }; 231 }); 232 233 var isString = (index$1 && typeof index$1 === 'object' && 'default' in index$1 ? index$1['default'] : index$1); 234 235 /** 236 * Parses a format string or object and returns format obj for use in rendering 237 * 238 * `format` is either a string with the default (positive) format, or object 239 * containing `pos` (required), `neg` and `zero` values 240 * 241 * Either string or format.pos must contain "%v" (value) to be valid 242 * 243 * @method _checkCurrencyFormat 244 * @for accounting 245 * @param {String} [format="%s%v"] String with the format to apply, where %s is the currency symbol and %v is the value. 246 * @return {Object} object represnting format (with pos, neg and zero attributes) 247 */ 248 function _checkCurrencyFormat(format) { 249 // Format should be a string, in which case `value` ('%v') must be present: 250 if (isString(format) && format.match('%v')) { 251 // Create and return positive, negative and zero formats: 252 return { 253 pos: format, 254 neg: format.replace('-', '').replace('%v', '-%v'), 255 zero: format 256 }; 257 } 258 259 // Otherwise, assume format was fine: 260 return format; 261 } 262 263 /** 264 * Format a number into currency 265 * 266 * Usage: accounting.formatMoney(number, symbol, precision, thousandsSep, decimalSep, format) 267 * defaults: (0, '$', 2, ',', '.', '%s%v') 268 * 269 * Localise by overriding the symbol, precision, thousand / decimal separators and format 270 * 271 * ```js 272 * // Default usage: 273 * accounting.formatMoney(12345678); // $12,345,678.00 274 * 275 * // European formatting (custom symbol and separators), can also use options object as second parameter: 276 * accounting.formatMoney(4999.99, { symbol: "â¬", precision: 2, thousand: ".", decimal: "," }); // â¬4.999,99 277 * 278 * // Negative values can be formatted nicely: 279 * accounting.formatMoney(-500000, { symbol: "£ ", precision: 0 });
279 // £ -500,000 280 * 281 * // Simple `format` string allows control of symbol position (%v = value, %s = symbol): 282 * accounting.formatMoney(5318008, { symbol: "GBP", format: "%v %s" }); // 5,318,008.00 GBP 283 * ``` 284 * 285 * @method formatMoney 286 * @for accounting 287 * @param {Number} number Number to be formatted. 288 * @param {Object} [opts={}] Object containing all the options of the method. 289 * @return {String} The given number properly formatted as money. 290 */ 291 function formatMoney(number) { 292 var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 293 294 // Resursively format arrays: 295 if (Array.isArray(number)) { 296 return number.map(function (val) { 297 return formatMoney(val, opts); 298 }); 299 } 300 301 // Build options object from second param (if object) or all params, extending defaults: 302 opts = objectAssign({}, settings, opts); 303 304 // Check format (returns object with pos, neg and zero): 305 var formats = _checkCurrencyFormat(opts.format); 306 307 // Choose which format to use for this value: 308 var useFormat = undefined; 309 310 if (number > 0) { 311 useFormat = formats.pos; 312 } else if (number < 0) { 313 useFormat = formats.neg; 314 } else { 315 useFormat = formats.zero; 316 } 317 318 // Return with currency symbol added: 319 return useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(number), opts)); 320 } 321 322 /** 323 * Format a list of numbers into an accounting column, padding with whitespace 324 * to line up currency symbols, thousand separators and decimals places 325 * 326 * List should be an array of numbers 327 * 328 * Returns array of accouting-formatted number strings of same length 329 * 330 * NB: `white-space:pre` CSS rule is required on the list container to prevent 331 * browsers from collapsing the whitespace in the output strings. 332 * 333 * ```js 334 * accounting.formatColumn([123.5, 3456.49, 777888.99, 12345678, -5432], { symbol: "$ " }); 335 * ``` 336 * 337 * @method formatColumn 338 * @for accounting 339 * @param {Array<Number>} list An array of numbers to format 340 * @param {Object} [opts={}] Object containing all the options of the method. 341 * @param {Object|String} [symbol="$"] String with the currency symbol. For conveniency if can be an object containing all the options of the method. 342 * @param {Integer} [precision=2] Number of decimal digits 343 * @param {String} [thousand=','] String with the thousands separator. 344 * @param {String} [decimal="."] String with the decimal separator. 345 * @param {String} [format="%s%v"] String with the format to apply, where %s is the currency symbol and %v is the value. 346 * @return {Array<String>} array of accouting-formatted number strings of same length 347 */ 348 function formatColumn(list) { 349 var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 350 351 if (!list) return []; 352 353 // Build options object from second param (if object) or all params, extending defaults: 354 opts = objectAssign({}, settings, opts); 355 356 // Check format (returns object with pos, neg and zero), only need pos for now: 357 var formats = _checkCurrencyFormat(opts.format); 358 359 // Whether to pad at start of string or after currency symbol: 360 var padAfterSymbol = formats.pos.indexOf('%s') < formats.pos.indexOf('%v'); 361 362 // Store value for the length of the longest string in the column: 363 var maxLength = 0; 364 365 // Format the list according to options, store the length of the longest string: 366 var formatted = list.map(function (val) { 367 if (Array.isArray(val)) { 368 // Recursively format columns if list is a multi-dimensional array: 369 return formatColumn(val, opts); 370 } 371 // Clean up the value 372 val = unformat(val, opts.decimal); 373 374 // Choose which format to use for this value (pos, neg or zero): 375 var useFormat = undefined; 376 377 if (val > 0) { 378 useFormat = formats.pos; 379 } else if (val < 0) { 380 useFormat = formats.neg; 381 } else { 382 useFormat = formats.zero; 383 } 384 385 // Format this value, push into formatted list and save the length: 386 var fVal = useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(val), opts)); 387 388 if (fVal.length > maxLength) { 389 maxLength = fVal.length; 390 } 391 392 return fVal; 393 }); 394 395 // Pad each number in the list and send back the column of numbers: 396 return formatted.map(function (val) { 397 // Only if this is a string (not a nested array, which would have already been padded): 398 if (isString(val) && val.length < maxLength) { 399 // Depending on symbol position, pad after symbol or at index 0: 400 return padAfterSymbol ? val.replace(opts.symbol, opts.symbol + new Array(maxLength - val.length + 1).join(' ')) : new Array(maxLength - val.length + 1).join(' ') + val; 401 } 402 return val; 403 }); 404 } 405 406 exports.settings = settings; 407 exports.unformat = unformat; 408 exports.toFixed = toFixed; 409 exports.formatMoney = formatMoney; 410 exports.formatNumber = formatNumber; 411 exports.formatColumn = formatColumn; 412 exports.format = formatMoney; 413 exports.parse = unformat; 414 415})); 416//# sourceMappingURL=accounting.umd.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.