From 576e64c8294fc66cf5576cd171113b535811f926 Mon Sep 17 00:00:00 2001 From: "Dmitry Iv." Date: Sun, 9 Feb 2025 19:17:43 -0500 Subject: [PATCH 1/4] Safeguard RE --- index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 7d38fa1..075119b 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ import en from './locale/en.js' -const durationRE = /(-?(?:\d+\.?\d*|\d*\.?\d+)(?:e[-+]?\d+)?)\s*([\p{L}]*)/uig +const durationRE = /(-?(?:\d{1,16}(?:\.\d{1,16})?|\.\d{1,16})(?:[eE][-+]?\d{1,4})?)\s?([\p{L}]{0,14})/gu parse.unit = en @@ -12,6 +12,9 @@ parse.unit = en * @return {Number} */ export default function parse(str = '', format = 'ms') { + // 10KB limit + // if (str.length > 10 * 1024) throw new Error("Input exceeds maximum allowed length"); + let result = null, prevUnits (str + '') From 04fc1b3dfb2a2d12f5c36f1c17ebe4adfe371c08 Mon Sep 17 00:00:00 2001 From: "Dmitry Iv." Date: Mon, 10 Feb 2025 12:07:58 -0500 Subject: [PATCH 2/4] Use dynamic cleanup regex --- index.js | 10 +++------- locale/en.js | 1 + test.js | 14 +++++++------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index 075119b..67719fe 100644 --- a/index.js +++ b/index.js @@ -12,15 +12,11 @@ parse.unit = en * @return {Number} */ export default function parse(str = '', format = 'ms') { - // 10KB limit - // if (str.length > 10 * 1024) throw new Error("Input exceeds maximum allowed length"); - let result = null, prevUnits - (str + '') - .replace(/(\d)[_ ](\d)/g, '$1$2') // ignore placeholders - .replaceAll(parse.unit.group, '') // remove group separator - .replaceAll(parse.unit.decimal, '.') // normalize decimal separator + String(str) + .replace(new RegExp(`(?<=\\d)[${parse.unit.placeholder}${parse.unit.group}](?=\\d)`, 'g'), '') // clean up group separators / placeholders + .replace(parse.unit.decimal, '.') // normalize decimal separator .replace(durationRE, (_, n, units) => { // if no units, find next smallest units or fall back to format value // eg. 1h30 -> 1h30m diff --git a/locale/en.js b/locale/en.js index f9595ed..802fbde 100644 --- a/locale/en.js +++ b/locale/en.js @@ -14,5 +14,6 @@ unit.nanosecond = unit.nanosec = unit.ns = 1e-6 unit.group = ',' unit.decimal = '.' +unit.placeholder = ' _' export default unit diff --git a/test.js b/test.js index 6d18f8d..f846782 100644 --- a/test.js +++ b/test.js @@ -167,15 +167,15 @@ t('locales', t => { t('locale separators', t => { parse.unit = en t.equal(parse('3.14 seconds'), 3140) - t.equal(parse('"1,23,456.789 seconds'), 123456789) - t.equal(parse('"1,23,456.789s'), 123456789) - t.equal(parse('"30,000.65 seconds'), 30000650) + t.equal(parse('1,23,456.789 seconds'), 123456789) + t.equal(parse('1,23,456.789s'), 123456789) + t.equal(parse('30,000.65 seconds'), 30000650) parse.unit = de t.equal(parse('3,14 seconds'), 3140) - t.equal(parse('"123.456,789 seconds'), 123456789) - t.equal(parse('"30.000,65 seconds'), 30000650) - t.equal(parse('"30 000,65 seconds'), 30000650) - t.equal(parse('"30_000,65 seconds'), 30000650) + t.equal(parse('123.456,789 seconds'), 123456789) + t.equal(parse('30.000,65 seconds'), 30000650) + t.equal(parse('30 000,65 seconds'), 30000650) + t.equal(parse('30_000,65 seconds'), 30000650) t.end() }) From 1d8086e599cc3c0c024e492bf595bd00bb4fadf3 Mon Sep 17 00:00:00 2001 From: "Dmitry Iv." Date: Mon, 10 Feb 2025 19:00:30 -0500 Subject: [PATCH 3/4] Minot perf optimization attempt --- index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 67719fe..bba3cb2 100644 --- a/index.js +++ b/index.js @@ -1,36 +1,36 @@ import en from './locale/en.js' -const durationRE = /(-?(?:\d{1,16}(?:\.\d{1,16})?|\.\d{1,16})(?:[eE][-+]?\d{1,4})?)\s?([\p{L}]{0,14})/gu +const durationRE = /((?:\d{1,16}(?:\.\d{1,16})?|\.\d{1,16})(?:[eE][-+]?\d{1,4})?)\s?([\p{L}]{0,14})/gu parse.unit = en /** * convert `str` to ms * - * @param {String} str - * @param {String} format - * @return {Number} + * @param {string} str + * @param {string} format + * @return {number} */ export default function parse(str = '', format = 'ms') { let result = null, prevUnits String(str) - .replace(new RegExp(`(?<=\\d)[${parse.unit.placeholder}${parse.unit.group}](?=\\d)`, 'g'), '') // clean up group separators / placeholders + .replace(new RegExp(`(\\d)[${parse.unit.placeholder}${parse.unit.group}](\\d)`, 'g'), '$1$2') // clean up group separators / placeholders .replace(parse.unit.decimal, '.') // normalize decimal separator .replace(durationRE, (_, n, units) => { // if no units, find next smallest units or fall back to format value // eg. 1h30 -> 1h30m if (!units) { if (prevUnits) { - for (var u in parse.unit) if (parse.unit[u] < prevUnits) { units = u; break } + for (const u in parse.unit) if (parse.unit[u] < prevUnits) { units = u; break } } else units = format } else units = units.toLowerCase() - units = parse.unit[units] || parse.unit[units.replace(/s$/, '')] + prevUnits = units = parse.unit[units] || parse.unit[units.replace(/s$/, '')] - if (units) result = (result || 0) + Math.abs(parseFloat(n, 10)) * units, prevUnits = units + if (units) result = (result || 0) + n * units }) return result && ((result / (parse.unit[format] || 1)) * (str[0] === '-' ? -1 : 1)) From 2a340b5bcb727fe34ceb0bcbd7e01b1c65bde484 Mon Sep 17 00:00:00 2001 From: "Dmitry Iv." Date: Tue, 11 Feb 2025 07:51:55 -0500 Subject: [PATCH 4/4] Make rewritable type --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index e7fc8d6..09a2b94 100644 --- a/index.d.ts +++ b/index.d.ts @@ -22,7 +22,7 @@ declare module './locale/*.js' { declare const durationRE: RegExp; declare namespace parse { - const unit: Units; + let unit: Units; } /**