From 05e5963d6baf874193dcf4476d821e9109b3e905 Mon Sep 17 00:00:00 2001 From: "ala'n (Alexey Stsefanovich)" Date: Wed, 7 Aug 2024 17:26:24 +0200 Subject: [PATCH] feat(esl-utils): add `parseTime` alternative, less restrictive to passed format --- src/modules/esl-utils/misc/format.ts | 16 ++++-- .../esl-utils/misc/test/format.test.ts | 56 ++++++++++++++++++- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/modules/esl-utils/misc/format.ts b/src/modules/esl-utils/misc/format.ts index 5cc3aa36f..534db7199 100644 --- a/src/modules/esl-utils/misc/format.ts +++ b/src/modules/esl-utils/misc/format.ts @@ -90,17 +90,25 @@ export function format(str: string, source: Record, matcher: RegExp } /** * Parses time string ([CSS style](https://developer.mozilla.org/en-US/docs/Web/CSS/time)) + * Less strict than CSS spec, allows empty string, numbers without units, ending dot. * @example * `.3s`, `4.5s`, `1000ms` * @returns number - time in milliseconds */ -export function parseCSSTime(timeStr: string): number { +export function parseTime(timeStr: string): number { const str = timeStr.trim().toLowerCase(); - if (!/\dm?s$/.test(str)) return NaN; - if (str.endsWith('ms')) return +str.slice(0, -2); - return +str.slice(0, -1) * 1000; + const parseNoEmpty = (s: string): number => s ? +s : NaN; + if (str.endsWith('ms')) return parseNoEmpty(str.slice(0, -2)); + if (str.endsWith('s')) return parseNoEmpty(str.slice(0, -1)) * 1000; + return +str; // empty string without unit is treated as 0 } +/** + * Restrictive time parser according to [CSS style](https://developer.mozilla.org/en-US/docs/Web/CSS/time) spec. + * @see {@link parseTime} + */ +export const parseCSSTime = (timeStr: string): number => /(\d*\.?\d+)(ms|s)/i.test(timeStr) ? parseTime(timeStr) : NaN; + /** * Parses string of times ([CSS style](https://developer.mozilla.org/en-US/docs/Web/CSS/time)) * @example diff --git a/src/modules/esl-utils/misc/test/format.test.ts b/src/modules/esl-utils/misc/test/format.test.ts index a9c22f08a..feca05f84 100644 --- a/src/modules/esl-utils/misc/test/format.test.ts +++ b/src/modules/esl-utils/misc/test/format.test.ts @@ -9,6 +9,7 @@ import { parseNumber, parseBoolean, parseString, + parseTime, parseCSSTime, parseCSSTimeSet } from '../format'; @@ -146,7 +147,7 @@ describe('misc/format helper tests', () => { ); }); - describe('parseCSSTime', () => { + describe('parseTime', () => { test.each([ // Positive integer ['12s', 12000], @@ -165,6 +166,59 @@ describe('misc/format helper tests', () => { ['14S', 14000], // Zero with leading +/- ['+0s', 0], + ['-0ms', -0], + // Digits without unit should be parsed as milliseconds + ['0', 0], + ['100', 100], + // Leading zeros + ['012s', 12000], + ['0350ms', 350], + // Empty string + ['', 0], + // Extra dot + ['350.s', 350000] + ])( + 'valid time = %s parsed as %s', + (time: string, result: number) => expect(parseTime(time)).toBe(result) + ); + test.each([ + // Invalid text + 'five seconds', + 's', + 'ms', + ' s ', + ' ms ', + '350.n', + 'abc', + '-', + 'a', + // CSS time supports only seconds and milliseconds + '4min' + ])( + 'invalid time = %p parsed as NaN', + (time: string) => expect(parseTime(time)).toBe(NaN) + ); + }); + + describe('parseCSSTime', () => { + test.each([ + // Positive integer + ['12s', 12000], + ['350ms', 350], + ['1024ms', 1024], + [' 12s ', 12000], + [' 350ms ', 350], + // Non-integer + ['.3s', 300], + ['.124s', 124], + ['.3ms', 0.3], + // Negative integer + ['-456ms', -456], + // Case insensitive + ['14mS', 14], + ['14S', 14000], + // Zero with leading +/- + ['+0s', 0], ['-0ms', -0] ])( 'valid time = %s parsed as %s',