@technobuddha/library
Version:
A large library of useful functions
514 lines (513 loc) • 18.1 kB
JavaScript
"use strict";
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatNumber = void 0;
var defaultTo_1 = __importDefault(require("lodash/defaultTo"));
var map_1 = __importDefault(require("lodash/map"));
var constants_1 = require("../constants");
var padNumber_1 = __importDefault(require("../padNumber"));
var splitChars_1 = __importDefault(require("../splitChars"));
var build_1 = __importDefault(require("../build"));
function parse(mask) {
var scale = 1;
var beforeDP = true;
var before = [];
var after = [];
var group = false;
var commas = 0;
var zeroSeen = false;
var exponent = 0;
var signExponent = false;
var precision = 0;
var m = splitChars_1.default(mask);
for (var i = 0; i < m.length; ++i) {
var c = m[i];
switch (c) {
case '"': //literal string
case "'": {
var s = '"';
for (++i; i < mask.length; ++i) {
var k = mask.charAt(i);
if (c === k)
break;
s += k;
}
(beforeDP ? before : after).push(s);
break;
}
case '#': {
if (beforeDP) {
before.push(zeroSeen ? '0' : '#');
}
else {
precision++;
after.push('#');
}
break;
}
case '0': {
if (beforeDP) {
//If we see a 0 before the decimal point, all following #s are transformed into 0s
before.push('0');
zeroSeen = true;
}
else {
//if we see a 0 after the decimal point, the proceeding #s are transformed into 0s
precision++;
after = map_1.default(after, function (a) { return (a === '#' ? '0' : a); });
after.push('0');
}
break;
}
case ',': {
if (beforeDP)
commas++;
break;
}
case '.': {
beforeDP = false;
break;
}
case '%': {
scale *= 100;
(beforeDP ? before : after).push("\"" + c);
break;
}
case '‰': {
scale *= 1000;
(beforeDP ? before : after).push("\"" + c);
break;
}
case '‱': {
scale *= 10000;
(beforeDP ? before : after).push("\"" + c);
break;
}
case 'e':
case 'E': {
var signSeen = false;
var j = i + 1;
var e = 0;
if (mask.length > j && mask.charAt(j) === '+') {
j++;
signSeen = true;
}
else if (mask.length > j && mask.charAt(j) === '-') {
j++;
}
while (mask.length > j && mask.charAt(j) === '0') {
j++;
e++;
}
if (e > 0) {
i = j - 1;
exponent = e;
signExponent = signSeen;
(beforeDP ? before : after).push(c);
}
else {
(beforeDP ? before : after).push("\"" + c);
}
break;
}
case '\\': {
if (i < mask.length - 1)
(beforeDP ? before : after).push("\"" + mask.charAt(++i));
else
(beforeDP ? before : after).push('"\\');
break;
}
default: {
(beforeDP ? before : after).push("\"" + c);
break;
}
}
if (beforeDP && c !== ',') {
if (commas > 0)
group = true;
commas = 0;
}
}
scale = scale / Math.pow(1000, commas);
return {
aMask: after,
aDigits: after.reduce(function (acc, val) { return ((val === '0' || val === '#') ? acc + 1 : acc); }, 0),
bMask: before,
bDigits: before.reduce(function (acc, val) { return ((val === '0' || val === '#') ? acc + 1 : acc); }, 0),
scale: scale,
group: group,
exponent: exponent,
signExponent: signExponent,
precision: precision,
};
}
function format(input, _a) {
var round = _a.round, precision = _a.precision, scale = _a.scale, _b = _a.lead, lead = _b === void 0 ? 1 : _b, _c = _a.trim, trim = _c === void 0 ? 'none' : _c;
var sign = Math.sign(input);
var _d = __read(Math.abs(input).toExponential(15).split('e'), 2), m = _d[0], e = _d[1];
var exponent = Number(e) + 1; // +1 because we store the number without the decimal point
var mantissa = m.replace('.', constants_1.empty).split(constants_1.empty);
while (mantissa.length > exponent && mantissa[mantissa.length - 1] === '0')
--mantissa.length;
var rounder = function (n) {
if (mantissa.length < n) {
while (mantissa.length < n)
mantissa.push('0');
}
else {
var c = mantissa[n];
mantissa.length = n;
if (c > '4') {
for (;;) {
if (n < 0) {
mantissa.unshift('0');
++exponent;
n = 1;
}
var d = mantissa[--n];
if (d === '0') {
mantissa[n] = '1';
break;
}
if (d === '1') {
mantissa[n] = '2';
break;
}
if (d === '2') {
mantissa[n] = '3';
break;
}
if (d === '3') {
mantissa[n] = '4';
break;
}
if (d === '4') {
mantissa[n] = '5';
break;
}
if (d === '5') {
mantissa[n] = '6';
break;
}
if (d === '6') {
mantissa[n] = '7';
break;
}
if (d === '7') {
mantissa[n] = '8';
break;
}
if (d === '8') {
mantissa[n] = '9';
break;
}
if (d === '9') {
mantissa[n] = '0';
mantissa.unshift('1');
++exponent;
break;
}
process.stderr.write("\"" + d + "\"" + n + "\"");
}
}
}
};
if (scale !== undefined)
exponent += scale;
if (round !== undefined)
rounder(exponent + round);
if (precision !== undefined)
rounder(precision);
var length = Math.min(exponent, mantissa.length);
while (length < lead) {
mantissa.unshift('0');
++exponent;
++length;
}
if (trim === 'front' || trim === 'all') {
while (mantissa.length > 1 && mantissa[0] === '0') {
mantissa.shift();
--exponent;
}
}
if (trim === 'back' || trim === 'all') {
while (mantissa.length > exponent && mantissa[mantissa.length - 1] === '0')
--mantissa.length;
}
return new NumberFormatter(sign, mantissa, exponent);
}
var NumberFormatter = /** @class */ (function () {
function NumberFormatter(sign, mantissa, exponent) {
this.sign = sign;
this.mantissa = mantissa;
this.exponent = exponent;
this.output = [];
}
NumberFormatter.prototype.minus = function (negative, positive) {
if (positive === void 0) { positive = constants_1.empty; }
this.output.push(this.sign < 0 ? negative : positive);
return this;
};
NumberFormatter.prototype.grouped = function () {
var whole = this.mantissa.slice(0, this.exponent);
this.output.push(whole.map(function (c, i) { return (i > 0 && (whole.length - i) % 3 === 0 ? "," + c : c); }));
return this;
};
NumberFormatter.prototype.whole = function () {
var whole = this.mantissa.slice(0, this.exponent);
while (whole.length < this.exponent)
whole.push('0');
this.output.push(whole);
return this;
};
NumberFormatter.prototype.decimal = function () {
if (this.exponent < this.mantissa.length)
this.output.push('.');
return this;
};
NumberFormatter.prototype.fraction = function () {
this.output.push(this.mantissa.slice(this.exponent));
return this;
};
NumberFormatter.prototype.text = function (str) {
this.output.push(str);
return this;
};
NumberFormatter.prototype.scientific = function (e) {
this.output.push(this.mantissa[0], '.', this.mantissa.slice(1), e, this.exponent > 0 ? '+' : constants_1.empty, padNumber_1.default(this.exponent - 1, 3));
return this;
};
NumberFormatter.prototype.build = function () {
return build_1.default.apply(void 0, __spreadArray([], __read(this.output)));
};
return NumberFormatter;
}());
//#endregion
//#region formatNumber
function formatNumber(input, mask) {
var _a, e_1, _b;
if (/^([CDEFGNPX][0-9]*)|R$/ui.test(mask)) {
var f_1 = mask.charAt(0);
var prec = Number.parseInt(mask.slice(1), 10);
switch (f_1) {
case 'C':
case 'c': {
prec = defaultTo_1.default(prec, 2);
return format(input, { round: prec, lead: 1 }).minus('($', '$').grouped().decimal().fraction().minus(')').build();
}
case 'D':
case 'd': {
prec = defaultTo_1.default(prec, 2);
return format(input, { round: 0, lead: prec }).minus('-').whole().build();
}
case 'E':
case 'e': {
prec = defaultTo_1.default(prec, 6);
return format(input, { precision: prec + 1 }).minus('-').scientific(f_1).build();
}
case 'F':
case 'f': {
prec = defaultTo_1.default(prec, 2);
return format(input, { round: prec }).minus('-').whole().decimal().fraction().build();
}
case 'G':
case 'g': {
prec = defaultTo_1.default(prec, 15);
var sci = format(input, { precision: prec, trim: 'all' }).minus('-').scientific(f_1 === 'G' ? 'E' : 'e').build();
var fix = format(input, { precision: prec, trim: 'back' }).minus('-').whole().decimal().fraction().build();
return sci.length < fix.length ? sci : fix;
}
case 'N':
case 'n': {
prec = defaultTo_1.default(prec, 2);
return format(input, { round: prec }).minus('-').grouped().decimal().fraction().build();
}
case 'P':
case 'p': {
prec = defaultTo_1.default(prec, 2);
return format(input, { scale: 2, round: prec }).minus('-').whole().decimal().fraction().text(' %').build();
}
case 'R':
case 'r': {
for (var i = 1; i < 21; ++i) {
var num = input.toPrecision(i);
if (Number.parseFloat(num) === input)
return num;
}
break;
}
// No default
}
prec = defaultTo_1.default(prec, 0);
var hex = (input >>> 0).toString(16);
hex = hex.padStart(prec, '0');
if (f_1 === 'X')
hex = hex.toUpperCase();
return hex;
}
var formats = mask.toString().split(';');
var fmt = parse(formats[0]);
if (Number.parseFloat((input * fmt.scale).toFixed(fmt.precision)) === 0)
fmt = formats.length < 3 ? fmt : parse(formats[2]);
else if (input < 0)
fmt = formats.length < 2 ? parse("-" + formats[0]) : parse(formats[1]);
var w;
var f;
var exp = 0;
if (fmt.exponent > 0) {
var _c = __read(Math.abs(input).toExponential(fmt.aDigits + fmt.bDigits - 1).split('e'), 2), m = _c[0], e = _c[1];
(_a = __read(m.split('.').map(function (x) { return x.split(constants_1.empty); }), 2), w = _a[0], f = _a[1]);
exp = Number(e);
while (w.length < fmt.bDigits) {
w.push(f.shift());
exp--;
}
}
else if (fmt.bDigits === 0) {
w = (Math.abs(input * fmt.scale)).toFixed(0).split(constants_1.empty);
f = [];
}
else {
var scaled = Math.abs(input * fmt.scale);
var rescale = 0;
var str = void 0;
var split = void 0;
//toFixed for numbers greater than 1e21 return scientific notation...
while (scaled > 1e21) {
scaled /= 1e21;
rescale += 21;
}
if (rescale > 0) {
str = (scaled).toFixed(17);
split = str.split('.');
w = split[0].split(constants_1.empty);
f = split[1].split(constants_1.empty);
while (rescale-- > 0) {
w.push(f.shift());
f.push('0');
}
}
else {
str = (scaled).toFixed(fmt.aDigits);
split = str.split('.');
w = split[0].split(constants_1.empty); //whole part
f = split.length > 1 ? split[1].split(constants_1.empty) : []; //fractional
}
}
while (w.length > 0 && w[0] === '0')
w.shift();
var o = constants_1.empty;
var d = 0;
var b = fmt.bDigits;
for (var i = fmt.bMask.length - 1; i >= 0; --i) {
var x = fmt.bMask[i];
if (x === '0' || x === '#') {
if (fmt.group && d === 3 && w.length > 0) {
o = "," + o;
d = 0;
}
if (x === '0') {
o = w.length > 0 ? w.pop() + o : "0" + o;
d++;
b--;
}
else if (w.length > 0) {
o = w.pop() + o;
d++;
b--;
}
while (b <= 0 && w.length > 0) {
if (fmt.group && d === 3) {
o = "," + o;
d = 0;
}
o = w.pop() + o;
d++;
b--;
}
}
else if (x === 'e' || x === 'E') {
o = x + "-" + padNumber_1.default(Math.abs(exp), fmt.exponent) + o;
}
else {
o = x.slice(1) + o;
}
}
if (fmt.aMask.length > 0) {
var a = constants_1.empty;
var digits = false;
try {
for (var _d = __values(fmt.aMask), _e = _d.next(); !_e.done; _e = _d.next()) {
var x = _e.value;
switch (x) {
case '0': {
a = a + f.shift();
digits = true;
break;
}
case '#': {
if (f.reduce(function (acc, val) { return val === '0' ? acc : true; }, false)) {
a = a + f.shift();
digits = true;
}
break;
}
case 'e':
case 'E': {
a = a + x + ((fmt.signExponent || exp < 0) ? (exp < 0 ? '-' : '+') : constants_1.empty) + padNumber_1.default(Math.abs(exp), fmt.exponent);
break;
}
default: {
a = a + x.slice(1);
}
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_b = _d.return)) _b.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
o += digits ? "." + a : a;
}
return o;
}
exports.formatNumber = formatNumber;
//#endregion
exports.default = formatNumber;