Skip to content

Commit

Permalink
Merge pull request #9 from gae-labs/feature/better-format
Browse files Browse the repository at this point in the history
[+Add] Completely new format() function
  • Loading branch information
paradox-glitch authored Oct 15, 2024
2 parents 7a11e91 + 0399697 commit 964dcff
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 123 deletions.
21 changes: 21 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//* OLD CONFIG FROM package.json
// "eslintConfig": {
// "extends": "eslint:recommended",
// "env": {
// "node": true,
// "es6": true
// }
// },

// * NEW CONFIG

const js = require('@eslint/js');
module.exports = {
rules: js.configs.recommended.rules,
languageOptions: {
globals: {
require: true,
module: true,
},
},
};
242 changes: 199 additions & 43 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ var M = y / 12;
*
* Options:
*
* - `long` verbose formatting [false]
* - `long` verbose formatting [false] (Example: 5 hours instead of 5h)
* - `compact` compact formatting [false] (Example: 5h30m instead of 5h 30m)
* - `extraSpace` add extra space between value and unit [true with long and false when !long, unless specified] (Example: 5 h instead of 5h)
* - `exclude` array of units to exclude [] (Acceptable Inputs: [y, M, w, d, h, m, s, ms])
* - `plural` pluralize unit [true] [only works with long] (Example: 2 years instead of 2 year)
* - `short` provide only the most significant unit [false] (Example: 5h 30m 10s would be shown as 5h)
* - `minimum` minimum amount of a unit required to include that unit [1] (Acceptable Inputs: >= 1) (Example: Input of 1h 30m - Minimum 1 = 1h 30m | Minimum 2 = 90m | Minimum 1.5 = 1h 30m)
* - `object` To return an object with each unit and value [false] (Expected Output: { y: 1, M: 2, w: 3, d: 4, h: 5, m: 6, s: 7, ms: 8 })
*
* @param {String|Number} val
* @param {Object} [options]
Expand All @@ -30,11 +37,11 @@ module.exports = function (val, options) {
if (type === 'string' && val.length > 0) {
return parse(val);
} else if (type === 'number' && isFinite(val)) {
return options.long ? fmtLong(val) : fmtShort(val);
return format(val, options);
}
throw new Error(
'val is not a non-empty string or a valid number. val=' +
JSON.stringify(val)
JSON.stringify(val),
);
};

Expand All @@ -49,7 +56,8 @@ module.exports = function (val, options) {
function parse(str) {
str = String(str);

const l_Regex = /(?:(-?\d*\.?\d*)\s*(?:years?|yrs?|y)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:months?|mos?|mths?)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:weeks?|w)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:days?|d)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:hours?|hrs?|h)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:minutes?|mins?|m(?!s|i))(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:seconds?|secs?|s)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:milliseconds?|msecs?|ms|$))?/gim;
const l_Regex =
/(?:(-?\d*\.?\d*)\s*(?:years?|yrs?|y)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:months?|mos?|mths?)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:weeks?|w)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:days?|d)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:hours?|hrs?|h)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:minutes?|mins?|m(?!s|i))(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:seconds?|secs?|s)(?![A-Za-z]))?\s*(?:(-?\d*\.?\d*)\s*(?:milliseconds?|msecs?|ms|$))?/gim;

const l_Match = l_Regex.exec(str);

Expand Down Expand Up @@ -93,60 +101,208 @@ function parse(str) {
}

/**
* Short format for `ms`.
* Format for `ms`.
*
* Options:
*
* - `long` verbose formatting [false] (Example: 5 hours instead of 5h)
* - `compact` compact formatting [false] (Example: 5h30m instead of 5h 30m)
* - `extraSpace` add extra space between value and unit [true with long and false when !long, unless specified] (Example: 5 h instead of 5h)
* - `exclude` array of units to exclude [] (Acceptable Inputs: [y, M, w, d, h, m, s, ms])
* - `plural` pluralize unit [true] [only works with long] (Example: 2 years instead of 2 year)
* - `short` provide only the most significant unit [false] (Example: 5h 30m 10s would be shown as 5h)
* - `minimum` minimum amount of a unit required to include that unit [1] (Acceptable Inputs: >= 1) (Example: Input of 1h 30m - Minimum 1 = 1h 30m | Minimum 2 = 90m | Minimum 1.5 = 1h 30m)
* - `object` To return an object with each unit and value [false] (Expected Output: { y: 1, M: 2, w: 3, d: 4, h: 5, m: 6, s: 7, ms: 8 })
*
* @param {Number} ms
* @param {Object} [options]
* @return {String}
* @api private
*/
function format(ms, options) {
options = options || {};
options.plural = options.plural === undefined ? true : options.plural;
options.extraSpace =
options.extraSpace === undefined
? options.long
? true
: false
: options.extraSpace;
options.minimum = options.minimum < 1 ? 1 : options.minimum || 1;

function fmtShort(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return Math.round(ms / d) + 'd';
}
if (msAbs >= h) {
return Math.round(ms / h) + 'h';
var msAbs = Math.round(Math.abs(ms));
var l_Result = '';
var l_Object = {};

if (
(msAbs >= y * options.minimum || msAbs == y) &&
(!options.exclude || !options.exclude.includes('y'))
) {
const l_Value = Math.floor(msAbs / y);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'years'
: 'year'
: 'years'
: 'y') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * y;
l_Object.y = l_Value;
}
if (msAbs >= m) {
return Math.round(ms / m) + 'm';

if (
(msAbs >= M * options.minimum || msAbs == M) &&
(!options.exclude || !options.exclude.includes('M')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = Math.floor(msAbs / M);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'months'
: 'month'
: 'months'
: 'M') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * M;
l_Object.M = l_Value;
}
if (msAbs >= s) {
return Math.round(ms / s) + 's';

if (
(msAbs >= w * options.minimum || msAbs == w) &&
(!options.exclude || !options.exclude.includes('w')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = Math.floor(msAbs / w);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'weeks'
: 'week'
: 'weeks'
: 'w') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * w;
l_Object.w = l_Value;
}
return ms + 'ms';
}

/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
if (
(msAbs >= d * options.minimum || msAbs == d) &&
(!options.exclude || !options.exclude.includes('d')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = Math.floor(msAbs / d);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'days'
: 'day'
: 'days'
: 'd') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * d;
l_Object.d = l_Value;
}

function fmtLong(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return plural(ms, msAbs, d, 'day');
if (
(msAbs >= h * options.minimum || msAbs == h) &&
(!options.exclude || !options.exclude.includes('h')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = Math.floor(msAbs / h);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'hours'
: 'hour'
: 'hours'
: 'h') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * h;
l_Object.h = l_Value;
}
if (msAbs >= h) {
return plural(ms, msAbs, h, 'hour');

if (
(msAbs >= m * options.minimum || msAbs == m) &&
(!options.exclude || !options.exclude.includes('m')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = Math.floor(msAbs / m);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'minutes'
: 'minute'
: 'minutes'
: 'm') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * m;
l_Object.m = l_Value;
}
if (msAbs >= m) {
return plural(ms, msAbs, m, 'minute');

if (
(msAbs >= s * options.minimum || msAbs == s) &&
(!options.exclude || !options.exclude.includes('s')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = Math.floor(msAbs / s);
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'seconds'
: 'second'
: 'seconds'
: 's') +
(options.compact ? '' : ' ');
msAbs = msAbs - l_Value * s;
l_Object.s = l_Value;
}
if (msAbs >= s) {
return plural(ms, msAbs, s, 'second');

if (
msAbs > 0 &&
(!options.exclude || !options.exclude.includes('ms')) &&
!(options.short && l_Result.length > 0)
) {
const l_Value = msAbs;
l_Result +=
l_Value +
(options.extraSpace ? ' ' : '') +
(options.long
? options.plural
? l_Value != 1
? 'milliseconds'
: 'millisecond'
: 'milliseconds'
: 'ms') +
(options.compact ? '' : ' ');
l_Object.ms = l_Value;
}
return ms + ' ms';
}

/**
* Pluralization helper.
*/
if (ms < 0) l_Result = '-' + l_Result;
if (ms < 0) l_Object.negative = true;

function plural(ms, msAbs, n, name) {
var isPlural = msAbs >= n * 1.5;
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
if (options.object) return l_Object;
else return l_Result.trim();
}
14 changes: 3 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,13 @@
],
"scripts": {
"precommit": "lint-staged",
"lint": "eslint lib/* bin/*",
"lint": "eslint *.js",
"test": "mocha tests.js"
},
"eslintConfig": {
"extends": "eslint:recommended",
"env": {
"node": true,
"es6": true
}
},
"lint-staged": {
"*.js": [
"npm run lint",
"prettier --single-quote --write",
"git add"
"prettier --single-quote --write"
]
},
"license": "MIT",
Expand All @@ -46,4 +38,4 @@
"ms"
],
"author": "gae-labs"
}
}
Loading

0 comments on commit 964dcff

Please sign in to comment.