"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 = ` ${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; };