Skip to content

Commit

Permalink
fix: reviews & formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
hugo082 committed Dec 27, 2024
1 parent 03feb0d commit f3b61e3
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 49 deletions.
1 change: 1 addition & 0 deletions docs/number/parseHumanDuration.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: parseHumanDuration
description: Parses a human duration string into milliseconds
since: 12.3.0
---

### Usage
Expand Down
78 changes: 45 additions & 33 deletions src/number/parseHumanDuration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isNumber } from 'radashi'

export type HumanQuantity<
Unit extends string,
ShortUnit extends string = never,
Expand All @@ -21,49 +23,55 @@ export type HumanQuantityOptions<
* Defines a parser for human quantity strings
*
* @see https://radashi.js.org/reference/number/parseHumanDuration
* @example
* ```ts
* const distanceParser = _.defineHumanQuantityParser({
* units: {
* kilometer: 1_000,
* mile: 1_852,
* yard: 0.9144,
* foot: 0.3048,
* meter: 1,
* },
* short: {
* km: 'kilometer',
* mi: 'mile',
* yd: 'yard',
* ft: 'foot',
* m: 'meter',
* },
* })
*
* distanceParser("1 kilometer") // => 1_000
* distanceParser("1 mile") // => 1_852
* distanceParser("1 yard") // => 0.9144
* distanceParser("1ft") // => 0.3048
* distanceParser("1 meter") // => 1
* ```
*/
* @example
* ```ts
* const distanceParser = _.defineHumanQuantityParser({
* units: {
* kilometer: 1_000,
* mile: 1_852,
* yard: 0.9144,
* foot: 0.3048,
* meter: 1,
* },
* short: {
* km: 'kilometer',
* mi: 'mile',
* yd: 'yard',
* ft: 'foot',
* m: 'meter',
* },
* })
*
* distanceParser("1 kilometer") // => 1_000
* distanceParser("1 mile") // => 1_852
* distanceParser("1 yard") // => 0.9144
* distanceParser("1ft") // => 0.3048
* distanceParser("1 meter") // => 1
* ```
*/
export function defineHumanQuantityParser<
Unit extends string,
ShortUnit extends string = never,
>({ units, short }: HumanQuantityOptions<Unit, ShortUnit>) {

return (quantity: HumanQuantity<Unit, ShortUnit>): number => {
const match = quantity.match(/^(-?\d+(?:\.\d+)?) ?(\w+)?s?$/)
if (!match) throw new Error(`Invalid quantity, cannot parse: ${quantity}`)
if (!match) {
throw new Error(`Invalid quantity, cannot parse: ${quantity}`)
}

let unit = match[2] as Unit | ShortUnit
unit = short && unit in short ? short[unit as ShortUnit] : (unit as Unit)

let count = Number.parseFloat(match[1])
if (Math.abs(count) > 1 && unit.endsWith('s'))
const count = Number.parseFloat(match[1])
if (Math.abs(count) > 1 && unit.endsWith('s')) {
unit = unit.substring(0, unit.length - 1) as Unit
}

if (!units[unit]) throw new Error(`Invalid unit: ${unit}, makes sure it is one of: ${Object.keys(units).join(', ')}`)
if (!units[unit]) {
throw new Error(
`Invalid unit: ${unit}, makes sure it is one of: ${Object.keys(units).join(', ')}`,
)
}

return count * units[unit]
}
Expand All @@ -88,8 +96,12 @@ export type HumanDuration = HumanQuantity<
* parseHumanDuration(500) // => 500
* ```
*/
export function parseHumanDuration(humanDuration: HumanDuration | number): number {
if (typeof humanDuration === 'number') return humanDuration
export function parseHumanDuration(
humanDuration: HumanDuration | number,
): number {
if (isNumber(humanDuration)) {
return humanDuration
}

const parser = defineHumanQuantityParser({
units: {
Expand Down
34 changes: 18 additions & 16 deletions tests/number/parseHumanDuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,22 @@ describe('parseHumanDuration', () => {
})

test('failures on invalid input', () => {
// @ts-expect-error
expect(() => _.parseHumanDuration('An invalid string')).toThrow(/Invalid quantity, cannot parse: An invalid string/)
// @ts-expect-error
expect(() => _.parseHumanDuration('abc weeks')).toThrow(/Invalid quantity, cannot parse: abc weeks/)
// @ts-expect-error
expect(() => _.parseHumanDuration('3 unknown')).toThrow(/Invalid unit: unknown, makes sure it is one of: week, day, hour, minute, second, millisecond/)
expect(() =>
_.parseHumanDuration('An invalid string' as _.HumanDuration),
).toThrow(/Invalid quantity, cannot parse: An invalid string/)
expect(() => _.parseHumanDuration('abc weeks' as _.HumanDuration)).toThrow(
/Invalid quantity, cannot parse: abc weeks/,
)
expect(() => _.parseHumanDuration('3 unknown' as _.HumanDuration)).toThrow(
/Invalid unit: unknown, makes sure it is one of: week, day, hour, minute, second, millisecond/,
)
})

test('is does nothing when parameter is alaready a number', () => {
expect(_.parseHumanDuration(50)).toBe(50)
})
})


describe('defineHumanQuantityParser', () => {
const distanceParser = _.defineHumanQuantityParser({
units: {
Expand All @@ -79,14 +81,14 @@ describe('defineHumanQuantityParser', () => {
})

test('returned values', () => {
expect(distanceParser("1 kilometer")).toBe(1_000)
expect(distanceParser("1km")).toBe(1_000)
expect(distanceParser("1 mile")).toBe(1_852)
expect(distanceParser("1mi")).toBe(1_852)
expect(distanceParser("1 yard")).toBe(0.9144)
expect(distanceParser("1yd")).toBe(0.9144)
expect(distanceParser("1 foot")).toBe(0.3048)
expect(distanceParser("1ft")).toBe(0.3048)
expect(distanceParser("1 meter")).toBe(1)
expect(distanceParser('1 kilometer')).toBe(1_000)
expect(distanceParser('1km')).toBe(1_000)
expect(distanceParser('1 mile')).toBe(1_852)
expect(distanceParser('1mi')).toBe(1_852)
expect(distanceParser('1 yard')).toBe(0.9144)
expect(distanceParser('1yd')).toBe(0.9144)
expect(distanceParser('1 foot')).toBe(0.3048)
expect(distanceParser('1ft')).toBe(0.3048)
expect(distanceParser('1 meter')).toBe(1)
})
})

0 comments on commit f3b61e3

Please sign in to comment.