|
|
|
"use strict";
|
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
toDisplay
|
|
|
|
conversion between unit scales (eg. IEC -> metric bytes)
|
|
|
|
*/
|
|
|
|
|
|
|
|
const util = require("util");
|
|
|
|
const chalk = require("chalk");
|
|
|
|
|
|
|
|
function capitalize(string) {
|
|
|
|
return string[0].toUpperCase() + string.slice(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = function makeUnits(unitSpecs) {
|
|
|
|
let resultObject = {};
|
|
|
|
|
|
|
|
unitSpecs.forEach((spec, i) => {
|
|
|
|
let proto = {
|
|
|
|
[util.inspect.custom]: function (_depth, options) {
|
|
|
|
let inspectString = `<Unit> ${this.amount} ${this.unit}`;
|
|
|
|
|
|
|
|
if (options.colors === true) {
|
|
|
|
return chalk.cyan(inspectString);
|
|
|
|
} else {
|
|
|
|
return inspectString;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
toString: function () {
|
|
|
|
return `${this.amount} ${this.unit}`;
|
|
|
|
},
|
|
|
|
toDisplay: function (decimals) {
|
|
|
|
let roundingFactor = Math.pow(10, decimals);
|
|
|
|
let unitMagnitude = i;
|
|
|
|
let amount = this.amount;
|
|
|
|
let unitsLeft = (i < unitSpecs.length - 1);
|
|
|
|
|
|
|
|
function createOfCurrentMagnitude() {
|
|
|
|
let roundedValue = Math.round(amount * roundingFactor) / roundingFactor;
|
|
|
|
|
|
|
|
return resultObject[unitSpecs[unitMagnitude].unit](roundedValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (unitsLeft === true) {
|
|
|
|
let currentUnit = unitSpecs[unitMagnitude];
|
|
|
|
|
|
|
|
if (amount < currentUnit.toNext) {
|
|
|
|
return createOfCurrentMagnitude();
|
|
|
|
} else {
|
|
|
|
amount = amount / currentUnit.toNext;
|
|
|
|
unitMagnitude += 1;
|
|
|
|
|
|
|
|
unitsLeft = (unitMagnitude < unitSpecs.length - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return createOfCurrentMagnitude;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
unitSpecs.forEach((otherSpec, otherI) => {
|
|
|
|
let factor = 1;
|
|
|
|
|
|
|
|
if (otherI < i) {
|
|
|
|
/* Convert downwards, to smaller units (== larger numbers) */
|
|
|
|
unitSpecs.slice(otherI, i).reverse().forEach((specStep) => {
|
|
|
|
factor = factor * specStep.toNext;
|
|
|
|
});
|
|
|
|
} else if (otherI > i) {
|
|
|
|
/* Convert upwards, to larger units (== smaller numbers) */
|
|
|
|
unitSpecs.slice(i, otherI).forEach((specStep) => {
|
|
|
|
factor = factor / specStep.toNext;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
proto[`to${capitalize(otherSpec.unit)}`] = function () {
|
|
|
|
return resultObject[otherSpec.unit](this.amount * factor);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
resultObject[spec.unit] = function createUnit(value) {
|
|
|
|
if (typeof value !== "number") {
|
|
|
|
throw new Error("Value must be numeric");
|
|
|
|
} else {
|
|
|
|
return Object.assign(Object.create(proto), {
|
|
|
|
unit: spec.unit,
|
|
|
|
amount: value
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
return resultObject;
|
|
|
|
};
|