(input: string)
| 31 | * argv-shape error (exit 129). |
| 32 | */ |
| 33 | export function parseDuration(input: string): number { |
| 34 | const raw = input.trim(); |
| 35 | if (raw === "") throw new RangeError("empty duration"); |
| 36 | |
| 37 | // A bare integer is seconds — preserve the historical contract. |
| 38 | if (/^\d+$/.test(raw)) { |
| 39 | const seconds = Number.parseInt(raw, 10); |
| 40 | if (seconds <= 0) throw new RangeError(`duration must be positive (got '${input}')`); |
| 41 | return seconds; |
| 42 | } |
| 43 | |
| 44 | // Otherwise require one or more <integer><unit> segments. No sign, |
| 45 | // no decimal point — TTLs are whole seconds. |
| 46 | const segment = /(\d+)([a-z])/giy; |
| 47 | let total = 0; |
| 48 | let consumed = 0; |
| 49 | for (let match = segment.exec(raw); match !== null; match = segment.exec(raw)) { |
| 50 | const [whole, digits, unit] = match; |
| 51 | const factor = UNIT_SECONDS[unit.toLowerCase()]; |
| 52 | if (factor === undefined) { |
| 53 | throw new RangeError(`unknown duration unit '${unit}' in '${input}'`); |
| 54 | } |
| 55 | total += Number.parseInt(digits, 10) * factor; |
| 56 | consumed += whole.length; |
| 57 | } |
| 58 | if (consumed !== raw.length) { |
| 59 | throw new RangeError(`invalid duration '${input}'`); |
| 60 | } |
| 61 | if (total <= 0) throw new RangeError(`duration must be positive (got '${input}')`); |
| 62 | return total; |
| 63 | } |
no test coverage detected