qte 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +274 -4
- package/dist/index.d.ts +244 -2
- package/dist/index.js +1 -10
- package/package.json +22 -8
package/README.md
CHANGED
|
@@ -1,10 +1,280 @@
|
|
|
1
|
-
|
|
2
1
|
<div align="center">
|
|
3
|
-
<h1 align="center">qte</h1>
|
|
2
|
+
<h1 align="center">⏱️ <code>qte</code></h1>
|
|
4
3
|
|
|
5
4
|
<p align="center">
|
|
6
|
-
<strong>
|
|
5
|
+
<strong>Parsing and formatting for human-readable time expressions.</strong>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/qte"><img src="https://img.shields.io/npm/v/qte" alt="npm version"></a>
|
|
10
|
+
<a href="https://pkg-size.dev/qte"><img src="https://pkg-size.dev/badge/bundle/qte" alt="bundle size"></a>
|
|
11
|
+
<a href="https://github.com/adelrodriguez/qte/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/qte" alt="license"></a>
|
|
7
12
|
</p>
|
|
8
13
|
</div>
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- Parse time strings into any unit (milliseconds, seconds, minutes, hours, days, weeks, months, years)
|
|
18
|
+
- Compound expressions (`"1h 30m"`, `"1 day, 6 hours"`)
|
|
19
|
+
- Format milliseconds back to human-readable strings with configurable precision
|
|
20
|
+
- Tree-shakeable named exports
|
|
21
|
+
- TypeScript `TimeExpression` type with compile-time checking and `isTimeExpression` / `isCompoundTimeExpression` guards
|
|
22
|
+
- Zero dependencies
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install qte
|
|
28
|
+
# or
|
|
29
|
+
bun add qte
|
|
30
|
+
# or
|
|
31
|
+
pnpm add qte
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { parse, format, ms, seconds, MS_PER_WEEK } from "qte"
|
|
38
|
+
|
|
39
|
+
parse("2 days, 6 hours") // 194_400_000
|
|
40
|
+
format(3_600_000) // "1h"
|
|
41
|
+
format(5_432_100, { precision: 3 }) // "1h 30m 32s"
|
|
42
|
+
format(5 * MS_PER_WEEK, { precision: 2 }) // "1mo 1w" (approximate)
|
|
43
|
+
ms("1h") // 3_600_000
|
|
44
|
+
seconds("30m") // 1800
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API
|
|
48
|
+
|
|
49
|
+
### `parse`
|
|
50
|
+
|
|
51
|
+
Parses a time expression and returns the value in milliseconds.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { parse } from "qte"
|
|
55
|
+
|
|
56
|
+
parse("1h") // 3_600_000
|
|
57
|
+
parse("30s") // 30_000
|
|
58
|
+
parse("1h 30m") // 5_400_000
|
|
59
|
+
parse("1 day, 6 hours, 30 minutes") // 109_800_000
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `format`
|
|
63
|
+
|
|
64
|
+
Converts milliseconds to a human-readable time expression.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { format } from "qte"
|
|
68
|
+
|
|
69
|
+
format(3_600_000) // "1h"
|
|
70
|
+
format(500) // "500ms"
|
|
71
|
+
format(0) // "0ms"
|
|
72
|
+
format(-3_600_000) // "-1h"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Options
|
|
76
|
+
|
|
77
|
+
| Option | Type | Default | Description |
|
|
78
|
+
| ----------- | --------- | ------- | ----------------------------------------- |
|
|
79
|
+
| `long` | `boolean` | `false` | Use verbose format (`"1 hour"` vs `"1h"`) |
|
|
80
|
+
| `precision` | `number` | `1` | Maximum number of unit segments to output |
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
format(3_600_000, { long: true }) // "1 hour"
|
|
84
|
+
format(5_432_100, { precision: 3 }) // "1h 30m 32s"
|
|
85
|
+
format(5_400_000, { long: true, precision: 2 }) // "1 hour 30 minutes"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### Precision
|
|
89
|
+
|
|
90
|
+
When `precision` is `1` (the default), the value is rounded to the single largest applicable unit. Higher values decompose the duration into multiple segments, with the last segment rounded to absorb the remainder.
|
|
91
|
+
|
|
92
|
+
If the value has fewer meaningful segments than the requested precision, only the meaningful segments are returned:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
format(3_600_000, { precision: 5 }) // "1h"
|
|
96
|
+
format(500, { precision: 10 }) // "500ms"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Month/year units use fixed average durations, so low precision can produce noticeable approximation around week/month boundaries:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
format(5 * MS_PER_WEEK, { precision: 2 }) // "1mo 1w" (approximate)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The output of `format` is always a valid input for `parse`:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const expr = format(5_400_000, { precision: 2 }) // "1h 30m"
|
|
109
|
+
parse(expr) // 5_400_000
|
|
110
|
+
|
|
111
|
+
const negativeExpr = format(-5_400_000, { precision: 2 }) // "-1h 30m"
|
|
112
|
+
parse(negativeExpr) // -5_400_000
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Unit Functions
|
|
116
|
+
|
|
117
|
+
Each function parses a single time expression and returns the value in the named unit. For compound expressions, use `parse` instead.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { ms, seconds, minutes, hours, days, weeks, months, years } from "qte"
|
|
121
|
+
|
|
122
|
+
ms("1s") // 1000
|
|
123
|
+
seconds("1h") // 3600
|
|
124
|
+
seconds("500ms") // 0.5
|
|
125
|
+
minutes("2h") // 120
|
|
126
|
+
hours("1d") // 24
|
|
127
|
+
days("1w") // 7
|
|
128
|
+
weeks("1y") // 52.1775
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `isTimeExpression`
|
|
132
|
+
|
|
133
|
+
Type guard that checks if a string is a valid single time expression. Returns `false` for compound expressions like `"1h 30m"`. Never throws.
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { isTimeExpression } from "qte"
|
|
137
|
+
|
|
138
|
+
isTimeExpression("1h") // true
|
|
139
|
+
isTimeExpression("500ms") // true
|
|
140
|
+
isTimeExpression("1h 30m") // false (use isCompoundTimeExpression)
|
|
141
|
+
isTimeExpression("hello") // false
|
|
142
|
+
|
|
143
|
+
const input: string = getUserInput()
|
|
144
|
+
if (isTimeExpression(input)) {
|
|
145
|
+
ms(input) // TypeScript knows `input` is TimeExpression
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### `isCompoundTimeExpression`
|
|
150
|
+
|
|
151
|
+
Checks if a string is a valid time expression (simple or compound). Never throws.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { isCompoundTimeExpression } from "qte"
|
|
155
|
+
|
|
156
|
+
isCompoundTimeExpression("1h") // true
|
|
157
|
+
isCompoundTimeExpression("1h 30m") // true
|
|
158
|
+
isCompoundTimeExpression("hello") // false
|
|
159
|
+
|
|
160
|
+
const input: string = getUserInput()
|
|
161
|
+
if (isCompoundTimeExpression(input)) {
|
|
162
|
+
parse(input) // input is a valid time expression
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Constants
|
|
167
|
+
|
|
168
|
+
Millisecond-based conversion factors for custom arithmetic (e.g. computing a cache TTL or rate limit window):
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import {
|
|
172
|
+
MS_PER_SECOND, // 1_000
|
|
173
|
+
MS_PER_MINUTE, // 60_000
|
|
174
|
+
MS_PER_HOUR, // 3_600_000
|
|
175
|
+
MS_PER_DAY, // 86_400_000
|
|
176
|
+
MS_PER_WEEK, // 604_800_000
|
|
177
|
+
MS_PER_MONTH, // 2_629_800_000
|
|
178
|
+
MS_PER_YEAR, // 31_557_600_000
|
|
179
|
+
} from "qte"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Compound Expressions
|
|
183
|
+
|
|
184
|
+
The parser supports multi-part expressions. Parts are summed together.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
// Space-separated
|
|
188
|
+
parse("1h 30m") // 5_400_000
|
|
189
|
+
|
|
190
|
+
// Comma-separated (single commas only)
|
|
191
|
+
parse("1h, 30m") // 5_400_000
|
|
192
|
+
|
|
193
|
+
// Concatenated (no separator)
|
|
194
|
+
parse("1h30m") // 5_400_000
|
|
195
|
+
|
|
196
|
+
// Long form
|
|
197
|
+
parse("1 hour 30 minutes") // 5_400_000
|
|
198
|
+
parse("1 year 2 weeks 5 days") // 32_594_400_000
|
|
199
|
+
|
|
200
|
+
// Duplicate units are additive
|
|
201
|
+
parse("1h 2h") // 10_800_000
|
|
202
|
+
|
|
203
|
+
// Order doesn't matter
|
|
204
|
+
parse("30m 1h") // 5_400_000
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Malformed delimiter punctuation is rejected (`",1h"`, `"1h,"`, `"1h,,30m"`, and `"1h, ,30m"` are invalid).
|
|
208
|
+
Numeric token pattern is `[+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?`, so exponent notation is supported.
|
|
209
|
+
|
|
210
|
+
### Supported Units
|
|
211
|
+
|
|
212
|
+
All units are case-insensitive. Spaces between number and unit are optional.
|
|
213
|
+
|
|
214
|
+
| Unit | Short | Aliases |
|
|
215
|
+
| ------------ | ----- | ---------------------------------------------- |
|
|
216
|
+
| Milliseconds | `ms` | `milliseconds`, `millisecond`, `msecs`, `msec` |
|
|
217
|
+
| Seconds | `s` | `seconds`, `second`, `secs`, `sec` |
|
|
218
|
+
| Minutes | `m` | `minutes`, `minute`, `mins`, `min` |
|
|
219
|
+
| Hours | `h` | `hours`, `hour`, `hrs`, `hr` |
|
|
220
|
+
| Days | `d` | `days`, `day` |
|
|
221
|
+
| Weeks | `w` | `weeks`, `week` |
|
|
222
|
+
| Months | `mo` | `months`, `month` |
|
|
223
|
+
| Years | `y` | `years`, `year`, `yrs`, `yr` |
|
|
224
|
+
|
|
225
|
+
### Signed Expressions
|
|
226
|
+
|
|
227
|
+
A leading sign applies to the entire compound expression when later parts are unsigned. Explicit signs on later segments override this and are evaluated per segment.
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
parse("-1h 30m") // -5_400_000
|
|
231
|
+
parse("+1h 30m") // 5_400_000
|
|
232
|
+
parse("-1h +30m") // -1_800_000
|
|
233
|
+
parse("-1h -30m") // -5_400_000
|
|
234
|
+
parse("-1h 30m -10m") // -2_400_000
|
|
235
|
+
parse("-1h 30m +10m") // -1_200_000
|
|
236
|
+
parse("1h-30m") // 1_800_000
|
|
237
|
+
parse("1h+30m") // 5_400_000
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Types
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import type { TimeExpression, FormatOptions, Unit } from "qte"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
- **`TimeExpression`** — A template literal type for single time expressions (`"1h"`, `"30s"`, `"500ms"`). Rejects invalid string literals at compile time. Used by unit functions (`ms`, `seconds`, etc.).
|
|
247
|
+
- **`FormatOptions`** — Options for `format()` (`long`, `precision`).
|
|
248
|
+
- **`Unit`** — Union of all recognized unit strings (e.g. `"hours"`, `"h"`, `"hr"`).
|
|
249
|
+
|
|
250
|
+
Use the type guards to validate strings at runtime:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
const input: string = getUserInput()
|
|
254
|
+
if (isTimeExpression(input)) {
|
|
255
|
+
ms(input) // `input` is narrowed to TimeExpression
|
|
256
|
+
}
|
|
257
|
+
if (isCompoundTimeExpression(input)) {
|
|
258
|
+
parse(input) // input is a valid expression (simple or compound)
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Error Handling
|
|
263
|
+
|
|
264
|
+
**`parse` and unit functions:**
|
|
265
|
+
|
|
266
|
+
- Throw a `TypeError` if the input is not a string, is empty, or exceeds 200 characters.
|
|
267
|
+
- Return `NaN` if the string cannot be parsed.
|
|
268
|
+
|
|
269
|
+
**`format`:**
|
|
270
|
+
|
|
271
|
+
- Throws a `TypeError` if the input is not a finite number (`Infinity`, `-Infinity`, `NaN`).
|
|
272
|
+
- Throws a `RangeError` if `precision` is not a finite positive integer (e.g. `0`, negative numbers, `NaN`, `Infinity`, or decimals).
|
|
273
|
+
|
|
274
|
+
**`isTimeExpression` and `isCompoundTimeExpression`:**
|
|
275
|
+
|
|
276
|
+
- Never throw. Return `false` for any invalid input.
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,244 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/** Milliseconds in one second (`1_000`). */
|
|
2
|
+
declare const MS_PER_SECOND = 1e3;
|
|
3
|
+
/** Milliseconds in one minute (`60_000`). */
|
|
4
|
+
declare const MS_PER_MINUTE: number;
|
|
5
|
+
/** Milliseconds in one hour (`3_600_000`). */
|
|
6
|
+
declare const MS_PER_HOUR: number;
|
|
7
|
+
/** Milliseconds in one day (`86_400_000`). */
|
|
8
|
+
declare const MS_PER_DAY: number;
|
|
9
|
+
/** Milliseconds in one week (`604_800_000`). */
|
|
10
|
+
declare const MS_PER_WEEK: number;
|
|
11
|
+
/** Milliseconds in one year (`31_557_600_000`), based on 365.25 days. */
|
|
12
|
+
declare const MS_PER_YEAR: number;
|
|
13
|
+
/** Milliseconds in one month (`2_629_800_000`), derived as one twelfth of a year. */
|
|
14
|
+
declare const MS_PER_MONTH: number;
|
|
15
|
+
/** Year unit aliases. */
|
|
16
|
+
type Years = "years" | "year" | "yrs" | "yr" | "y";
|
|
17
|
+
/** Month unit aliases. */
|
|
18
|
+
type Months = "months" | "month" | "mo";
|
|
19
|
+
/** Week unit aliases. */
|
|
20
|
+
type Weeks = "weeks" | "week" | "w";
|
|
21
|
+
/** Day unit aliases. */
|
|
22
|
+
type Days = "days" | "day" | "d";
|
|
23
|
+
/** Hour unit aliases. */
|
|
24
|
+
type Hours = "hours" | "hour" | "hrs" | "hr" | "h";
|
|
25
|
+
/** Minute unit aliases. */
|
|
26
|
+
type Minutes = "minutes" | "minute" | "mins" | "min" | "m";
|
|
27
|
+
/** Second unit aliases. */
|
|
28
|
+
type Seconds = "seconds" | "second" | "secs" | "sec" | "s";
|
|
29
|
+
/** Millisecond unit aliases. */
|
|
30
|
+
type Milliseconds = "milliseconds" | "millisecond" | "msecs" | "msec" | "ms";
|
|
31
|
+
/** Union of all recognized time unit strings. */
|
|
32
|
+
type Unit = Years | Months | Weeks | Days | Hours | Minutes | Seconds | Milliseconds;
|
|
33
|
+
/** Any casing variant of a time unit (lowercase, Capitalized, UPPERCASE). */
|
|
34
|
+
type UnitAnyCase = Unit | Capitalize<Unit> | Uppercase<Unit>;
|
|
35
|
+
/**
|
|
36
|
+
* A single time expression: a bare number, or a number followed by a unit
|
|
37
|
+
* (with or without a space).
|
|
38
|
+
*/
|
|
39
|
+
type TimeExpression = `${number}` | `${number}${UnitAnyCase}` | `${number} ${UnitAnyCase}`;
|
|
40
|
+
/** Options for {@link format}. */
|
|
41
|
+
interface FormatOptions {
|
|
42
|
+
/** Use verbose formatting (`"1 hour"` instead of `"1h"`). Defaults to `false`. */
|
|
43
|
+
long?: boolean;
|
|
44
|
+
/** Maximum number of unit segments to include. Defaults to `1`. */
|
|
45
|
+
precision?: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Format a millisecond value into a human-readable time expression.
|
|
49
|
+
*
|
|
50
|
+
* The returned string can be passed back into {@link parse} for
|
|
51
|
+
* round-trip conversion.
|
|
52
|
+
*
|
|
53
|
+
* @param milliseconds - The value in milliseconds to format
|
|
54
|
+
* @param options - Formatting options
|
|
55
|
+
* @returns A formatted time expression string
|
|
56
|
+
* @throws {TypeError} If the input is not a finite number
|
|
57
|
+
* @throws {RangeError} If `options.precision` is not a finite positive integer
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* format(3_600_000) // "1h"
|
|
62
|
+
* format(3_600_000, { long: true }) // "1 hour"
|
|
63
|
+
* format(500) // "500ms"
|
|
64
|
+
* format(5_432_100, { precision: 3 }) // "1h 30m 32s"
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare function format(milliseconds: number, options?: FormatOptions): string;
|
|
68
|
+
/**
|
|
69
|
+
* Check whether a string is a valid single time expression without throwing.
|
|
70
|
+
*
|
|
71
|
+
* Acts as a TypeScript type guard — when it returns `true`, the input is
|
|
72
|
+
* narrowed to {@link TimeExpression}. Unlike {@link isCompoundTimeExpression},
|
|
73
|
+
* this rejects compound expressions such as `"1h 30m"`.
|
|
74
|
+
*
|
|
75
|
+
* @param value - The string to validate
|
|
76
|
+
* @returns `true` if the string is a valid single time expression
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* isTimeExpression("1h") // true
|
|
81
|
+
* isTimeExpression("500ms") // true
|
|
82
|
+
* isTimeExpression("1h 30m") // false (compound)
|
|
83
|
+
* isTimeExpression("hello") // false
|
|
84
|
+
*
|
|
85
|
+
* const input: string = getUserInput()
|
|
86
|
+
* if (isTimeExpression(input)) {
|
|
87
|
+
* ms(input) // TypeScript knows `input` is TimeExpression
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function isTimeExpression(value: string): value is TimeExpression;
|
|
92
|
+
/**
|
|
93
|
+
* Check whether a string is a valid time expression (simple or compound)
|
|
94
|
+
* without throwing.
|
|
95
|
+
*
|
|
96
|
+
* This accepts both simple expressions (`"1h"`) and compound expressions
|
|
97
|
+
* (`"1h 30m"`).
|
|
98
|
+
*
|
|
99
|
+
* @param value - The string to validate
|
|
100
|
+
* @returns `true` if the string is a valid time expression
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* isCompoundTimeExpression("1h") // true
|
|
105
|
+
* isCompoundTimeExpression("1h 30m") // true
|
|
106
|
+
* isCompoundTimeExpression("hello") // false
|
|
107
|
+
* isCompoundTimeExpression("") // false
|
|
108
|
+
*
|
|
109
|
+
* const input: string = getUserInput()
|
|
110
|
+
* if (isCompoundTimeExpression(input)) {
|
|
111
|
+
* parse(input) // input is a valid time expression
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
declare function isCompoundTimeExpression(value: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Parse a time expression string into milliseconds.
|
|
118
|
+
*
|
|
119
|
+
* Accepts both simple (`"1h"`) and compound (`"1h 30m"`) expressions.
|
|
120
|
+
* Parts are summed together. Duplicate units are additive.
|
|
121
|
+
* Supports space separators, a single comma separator, or no separator.
|
|
122
|
+
* Numeric tokens support optional exponent notation (e.g. `"1e3ms"`).
|
|
123
|
+
* A leading sign on a compound expression applies to the whole expression
|
|
124
|
+
* unless later parts declare their own explicit signs.
|
|
125
|
+
*
|
|
126
|
+
* @param value - A time expression string to parse
|
|
127
|
+
* @returns The total value in milliseconds, or `NaN` if the string cannot be parsed
|
|
128
|
+
* @throws {TypeError} If the input is not a string, is empty, or exceeds 200 characters
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* parse("1h") // 3_600_000
|
|
133
|
+
* parse("30s") // 30_000
|
|
134
|
+
* parse("1h 30m") // 5_400_000
|
|
135
|
+
* parse("1 day, 6 hours, 30 minutes") // 109_800_000
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
declare function parse(value: string): number;
|
|
139
|
+
/**
|
|
140
|
+
* Parse a time expression and return the value in milliseconds.
|
|
141
|
+
*
|
|
142
|
+
* @param value - A time expression string
|
|
143
|
+
* @returns The value in milliseconds
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* ms("1s") // 1000
|
|
148
|
+
* ms("5m") // 300_000
|
|
149
|
+
* ms("1h") // 3_600_000
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare function ms(value: TimeExpression): number;
|
|
153
|
+
/**
|
|
154
|
+
* Parse a time expression and return the value in seconds.
|
|
155
|
+
*
|
|
156
|
+
* @param value - A time expression string
|
|
157
|
+
* @returns The value in seconds
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* seconds("1h") // 3600
|
|
162
|
+
* seconds("500ms") // 0.5
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
declare function seconds(value: TimeExpression): number;
|
|
166
|
+
/**
|
|
167
|
+
* Parse a time expression and return the value in minutes.
|
|
168
|
+
*
|
|
169
|
+
* @param value - A time expression string
|
|
170
|
+
* @returns The value in minutes
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* minutes("2h") // 120
|
|
175
|
+
* minutes("30s") // 0.5
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
declare function minutes(value: TimeExpression): number;
|
|
179
|
+
/**
|
|
180
|
+
* Parse a time expression and return the value in hours.
|
|
181
|
+
*
|
|
182
|
+
* @param value - A time expression string
|
|
183
|
+
* @returns The value in hours
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* hours("1d") // 24
|
|
188
|
+
* hours("30m") // 0.5
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
declare function hours(value: TimeExpression): number;
|
|
192
|
+
/**
|
|
193
|
+
* Parse a time expression and return the value in days.
|
|
194
|
+
*
|
|
195
|
+
* @param value - A time expression string
|
|
196
|
+
* @returns The value in days
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* days("1w") // 7
|
|
201
|
+
* days("12h") // 0.5
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
declare function days(value: TimeExpression): number;
|
|
205
|
+
/**
|
|
206
|
+
* Parse a time expression and return the value in weeks.
|
|
207
|
+
*
|
|
208
|
+
* @param value - A time expression string
|
|
209
|
+
* @returns The value in weeks
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* weeks("14d") // 2
|
|
214
|
+
* weeks("1y") // 52.1775
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
declare function weeks(value: TimeExpression): number;
|
|
218
|
+
/**
|
|
219
|
+
* Parse a time expression and return the value in months.
|
|
220
|
+
*
|
|
221
|
+
* @param value - A time expression string
|
|
222
|
+
* @returns The value in months
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* months("1y") // 12
|
|
227
|
+
* months("60d") // ~1.97
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
declare function months(value: TimeExpression): number;
|
|
231
|
+
/**
|
|
232
|
+
* Parse a time expression and return the value in years.
|
|
233
|
+
*
|
|
234
|
+
* @param value - A time expression string
|
|
235
|
+
* @returns The value in years
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* years("365.25d") // 1
|
|
240
|
+
* years("6mo") // 0.5
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
declare function years(value: TimeExpression): number;
|
|
244
|
+
export { years, weeks, seconds, parse, ms, months, minutes, isTimeExpression, isCompoundTimeExpression, hours, format, days, Years, Weeks, Unit, TimeExpression, Seconds, Months, Minutes, Milliseconds, MS_PER_YEAR, MS_PER_WEEK, MS_PER_SECOND, MS_PER_MONTH, MS_PER_MINUTE, MS_PER_HOUR, MS_PER_DAY, Hours, FormatOptions, Days };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
function main() {
|
|
3
|
-
return "Let's bake some pastry! \uD83E\uDD50";
|
|
4
|
-
}
|
|
5
|
-
export {
|
|
6
|
-
main
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
//# debugId=B3F3B1D74DE4157564756E2164756E21
|
|
10
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWwogICAgImV4cG9ydCBmdW5jdGlvbiBtYWluKCkge1xuICByZXR1cm4gXCJMZXQncyBiYWtlIHNvbWUgcGFzdHJ5ISDwn6WQXCJcbn1cbiIKICBdLAogICJtYXBwaW5ncyI6ICI7QUFBTyxTQUFTLElBQUksR0FBRztBQUFBLEVBQ3JCLE9BQU87QUFBQTsiLAogICJkZWJ1Z0lkIjogIkIzRjNCMUQ3NERFNDE1NzU2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
|
|
1
|
+
var B=1000,X=60000,F=3600000,G=86400000,H=604800000,f=31557600000,L=2629800000;var K=[{aliases:["years","year","yrs","yr","y"],long:"year",longPlural:"years",ms:f,short:"y"},{aliases:["months","month","mo"],long:"month",longPlural:"months",ms:L,short:"mo"},{aliases:["weeks","week","w"],long:"week",longPlural:"weeks",ms:H,short:"w"},{aliases:["days","day","d"],long:"day",longPlural:"days",ms:G,short:"d"},{aliases:["hours","hour","hrs","hr","h"],long:"hour",longPlural:"hours",ms:F,short:"h"},{aliases:["minutes","minute","mins","min","m"],long:"minute",longPlural:"minutes",ms:X,short:"m"},{aliases:["seconds","second","secs","sec","s"],long:"second",longPlural:"seconds",ms:B,short:"s"},{aliases:["milliseconds","millisecond","msecs","msec","ms"],long:"millisecond",longPlural:"milliseconds",ms:1,short:"ms"}];function S(y){return y.replaceAll(/[.*+?^${}()|[\]\\]/g,"\\$&")}var C=[...new Set(K.flatMap((y)=>y.aliases))],T=new Map(K.flatMap((y)=>y.aliases.map((k)=>[k,y.ms]))),V=C.toSorted((y,k)=>k.length-y.length).map((y)=>S(y)).join("|");function I(y){return T.get(y)??Number.NaN}function P(y){let k=K.at(y);if(!k)throw Error(`Invalid unit index: ${y}`);return k}function Z(y,k,_){if(_){let Y=Math.abs(y)===1?k.long:k.longPlural;return`${y} ${Y}`}return`${y}${k.short}`}function c(y,k){if(typeof y!=="number"||!Number.isFinite(y))throw TypeError(`Value provided to format() must be a finite number. Received: ${String(y)}`);let _=k?.long??!1,Y=k?.precision??1;if(!Number.isFinite(Y)||!Number.isInteger(Y)||Y<1)throw RangeError(`Option "precision" must be a finite positive integer. Received: ${String(Y)}`);if(y===0)return Z(0,P(K.length-1),_);let $=y<0,D=Math.abs(y);if(Y===1)return d(y,D,_);return m(D,$,_,Y)}function d(y,k,_){let Y=y<0?-1:1;for(let q of K)if(k>=q.ms){let M=Math.round(k/q.ms),j=M===0?0:Y*M;return Z(j,q,_)}let $=P(K.length-1),D=Math.round(k/$.ms),z=D===0?0:Y*D;return Z(z,$,_)}function m(y,k,_,Y){let $=y,D=[];for(let M=0;M<K.length&&D.length<Y;M+=1){let j=P(M);if(D.length===Y-1){let J=Math.round($/j.ms);if(J>0){D.push({unitIdx:M,value:J});break}continue}let w=Math.floor($/j.ms);if(w>0)D.push({unitIdx:M,value:w}),$-=w*j.ms}if(D.length===0){let M=P(K.length-1),j=Math.round(y/M.ms);D.push({unitIdx:K.length-1,value:j})}for(let M=D.length-1;M>=0;M-=1){let j=D[M],w=P(j.unitIdx),J=j.unitIdx-1;if(J<0)continue;let Q=P(J).ms/w.ms;if(j.value>=Q){let R=Math.floor(j.value/Q);j.value-=R*Q;let W=M>0?D[M-1]:void 0;if(W&&W.unitIdx===J)W.value+=R;else D.splice(M,0,{unitIdx:J,value:R}),M+=1}}while(D.length>1){let M=D.at(-1);if(!M||M.value!==0)break;D.pop()}if(D.length===0)return Z(0,P(K.length-1),_);if(D.every((M)=>M.value===0))return Z(0,P(K.length-1),_);let q=D.map((M)=>Z(M.value,P(M.unitIdx),_)).join(" ");return k?`-${q}`:q}var h=200,x=new RegExp(`([+-]?\\d*\\.?\\d+(?:e[+-]?\\d+)?)\\s*(${V})?`,"gi"),U=/^\s*$/,o=/^\s*,\s*$/;function p(y,k){if(U.test(y))return!0;if(k)return!1;return o.test(y)}function O(y){if(typeof y!=="string"||y.length===0||y.length>h)throw TypeError(`Value provided to parse() must be a string with length between 1 and ${h}. Received: ${String(y)}`);x.lastIndex=0;let k=0,_=0,Y=0,$=0,D=!1,z=!1,q=!1,M;while((M=x.exec(y))!==null){let A=y.slice(Y,M.index);if(!p(A,$===0))return Number.NaN;let Q=M[1]??"",R=M[2];if(!R)D=!0;let W=Q.startsWith("-")||Q.startsWith("+");if($===0)z=W;else if(W)q=!0;let E=Number.parseFloat(Q),b=R?I(R.toLowerCase()):1;if(!Number.isFinite(E)||Number.isNaN(b))return Number.NaN;let N=E*b;if(!Number.isFinite(N))return Number.NaN;if(k+=N,!Number.isFinite(k))return Number.NaN;if(_+=Math.abs(N),!Number.isFinite(_))return Number.NaN;Y=M.index+M[0].length,$+=1}if($===0)return Number.NaN;if($>1&&D)return Number.NaN;let j=y.slice(Y);if(!U.test(j))return Number.NaN;let w=y.trimStart(),J=w.startsWith("-")||w.startsWith("+");if($>1&&J&&z&&!q)return w.startsWith("-")?-_:_;return k}function v(y){return O(y)}function g(y){return O(y)/B}function r(y){return O(y)/X}function l(y){return O(y)/F}function s(y){return O(y)/G}function u(y){return O(y)/H}function n(y){return O(y)/L}function a(y){return O(y)/f}var t=new RegExp(`^[+-]?\\d*\\.?\\d+(?:e[+-]?\\d+)?(?: ?(?:${V}))?$`,"i");function i(y){try{if(!t.test(y))return!1;return!Number.isNaN(O(y))}catch{return!1}}function e(y){try{return!Number.isNaN(O(y))}catch{return!1}}export{a as years,u as weeks,g as seconds,O as parse,v as ms,n as months,r as minutes,i as isTimeExpression,e as isCompoundTimeExpression,l as hours,c as format,s as days,f as MS_PER_YEAR,H as MS_PER_WEEK,B as MS_PER_SECOND,L as MS_PER_MONTH,X as MS_PER_MINUTE,F as MS_PER_HOUR,G as MS_PER_DAY};
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qte",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Parse human-readable time expressions into any unit, and format durations into human-readable strings",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
6
|
+
"convert",
|
|
7
|
+
"duration",
|
|
8
|
+
"format",
|
|
9
|
+
"human-readable",
|
|
10
|
+
"milliseconds",
|
|
11
|
+
"ms",
|
|
12
|
+
"parse",
|
|
13
|
+
"time"
|
|
9
14
|
],
|
|
10
15
|
"homepage": "https://github.com/adelrodriguez/qte#readme",
|
|
11
16
|
"bugs": {
|
|
@@ -15,18 +20,27 @@
|
|
|
15
20
|
"author": "Adel Rodríguez",
|
|
16
21
|
"repository": {
|
|
17
22
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/adelrodriguez/qte.git"
|
|
23
|
+
"url": "git+https://github.com/adelrodriguez/qte.git"
|
|
19
24
|
},
|
|
20
25
|
"files": [
|
|
21
26
|
"dist"
|
|
22
27
|
],
|
|
23
28
|
"type": "module",
|
|
24
|
-
"
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"module": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
25
38
|
"scripts": {
|
|
26
39
|
"build": "bunup",
|
|
40
|
+
"build:debug": "bunup --sourcemap inline --no-minify",
|
|
27
41
|
"bump:deps": "bun update --interactive",
|
|
28
42
|
"check": "adamantite check",
|
|
29
|
-
"dev": "bunup --watch",
|
|
43
|
+
"dev": "bunup --watch --sourcemap inline --no-minify",
|
|
30
44
|
"fix": "adamantite fix",
|
|
31
45
|
"release": "changeset publish",
|
|
32
46
|
"init": "bun run --bun scripts/init.ts",
|