ts-time-utils 4.1.0 → 4.4.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 +81 -31
- package/dist/{age.js → age.cjs} +14 -6
- package/dist/{calculate.js → calculate.cjs} +30 -18
- package/dist/{calendar.js → calendar.cjs} +80 -39
- package/dist/{calendars.js → calendars.cjs} +48 -23
- package/dist/{chain.js → chain.cjs} +41 -40
- package/dist/{compare.js → compare.cjs} +58 -28
- package/dist/constants.cjs +19 -0
- package/dist/{countdown.js → countdown.cjs} +16 -7
- package/dist/{cron.js → cron.cjs} +20 -9
- package/dist/{dateRange.js → dateRange.cjs} +42 -26
- package/dist/{duration.js → duration.cjs} +56 -44
- package/dist/esm/chain.js +0 -5
- package/dist/esm/naturalLanguage.d.ts +1 -3
- package/dist/esm/naturalLanguage.d.ts.map +1 -1
- package/dist/esm/naturalLanguage.js +9 -2
- package/dist/esm/plugins.d.ts +0 -6
- package/dist/esm/plugins.d.ts.map +1 -1
- package/dist/esm/plugins.js +36 -42
- package/dist/esm/recurrence.d.ts.map +1 -1
- package/dist/esm/recurrence.js +3 -5
- package/dist/esm/timezone.d.ts +6 -1
- package/dist/esm/timezone.d.ts.map +1 -1
- package/dist/esm/timezone.js +106 -66
- package/dist/esm/types.d.ts +0 -4
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/{finance.js → finance.cjs} +39 -22
- package/dist/{fiscal.js → fiscal.cjs} +36 -17
- package/dist/{format.js → format.cjs} +83 -70
- package/dist/{healthcare.js → healthcare.cjs} +37 -22
- package/dist/{holidays.js → holidays.cjs} +52 -25
- package/dist/index.cjs +595 -0
- package/dist/{interval.js → interval.cjs} +24 -11
- package/dist/{iterate.js → iterate.cjs} +84 -41
- package/dist/{locale.js → locale.cjs} +54 -26
- package/dist/{naturalLanguage.js → naturalLanguage.cjs} +36 -23
- package/dist/naturalLanguage.d.ts +1 -3
- package/dist/naturalLanguage.d.ts.map +1 -1
- package/dist/{parse.js → parse.cjs} +24 -11
- package/dist/{performance.js → performance.cjs} +23 -10
- package/dist/{plugins.js → plugins.cjs} +48 -47
- package/dist/plugins.d.ts +0 -6
- package/dist/plugins.d.ts.map +1 -1
- package/dist/{precision.js → precision.cjs} +74 -37
- package/dist/{rangePresets.js → rangePresets.cjs} +40 -19
- package/dist/{recurrence.js → recurrence.cjs} +27 -21
- package/dist/recurrence.d.ts.map +1 -1
- package/dist/{scheduling.js → scheduling.cjs} +46 -31
- package/dist/{serialize.js → serialize.cjs} +36 -17
- package/dist/{temporal.js → temporal.cjs} +28 -13
- package/dist/{timezone.js → timezone.cjs} +140 -82
- package/dist/timezone.d.ts +6 -1
- package/dist/timezone.d.ts.map +1 -1
- package/dist/{types.js → types.cjs} +9 -3
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/{validate.js → validate.cjs} +54 -26
- package/dist/{workingHours.js → workingHours.cjs} +36 -17
- package/package.json +40 -37
- package/dist/constants.js +0 -16
- package/dist/index.js +0 -72
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Natural language date parsing utilities
|
|
3
4
|
* Provides intelligent parsing of human-readable date strings
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parseNaturalDate = parseNaturalDate;
|
|
8
|
+
exports.parseRelativePhrase = parseRelativePhrase;
|
|
9
|
+
exports.extractDatesFromText = extractDatesFromText;
|
|
10
|
+
exports.suggestDateFromContext = suggestDateFromContext;
|
|
11
|
+
const calculate_js_1 = require("./calculate.cjs");
|
|
12
|
+
const parse_js_1 = require("./parse.cjs");
|
|
7
13
|
/**
|
|
8
14
|
* Parses natural language date strings into Date objects
|
|
9
15
|
* @param input - Natural language date string
|
|
@@ -25,15 +31,15 @@ import { parseRelativeDate } from './parse.js';
|
|
|
25
31
|
* // Date for Dec 25 this year (or next if passed)
|
|
26
32
|
* ```
|
|
27
33
|
*/
|
|
28
|
-
|
|
29
|
-
const { referenceDate = new Date(), defaultTime } = options;
|
|
34
|
+
function parseNaturalDate(input, options = {}) {
|
|
35
|
+
const { referenceDate = new Date(), defaultTime, strict = false } = options;
|
|
30
36
|
const normalized = input.toLowerCase().trim();
|
|
31
37
|
// Try relative phrase parser first (handles "next week", "last month", etc.)
|
|
32
38
|
const relativePhraseResult = parseRelativePhrase(input, referenceDate);
|
|
33
39
|
if (relativePhraseResult)
|
|
34
40
|
return relativePhraseResult;
|
|
35
41
|
// Try existing relative date parser
|
|
36
|
-
const relativeResult = parseRelativeDate(input);
|
|
42
|
+
const relativeResult = (0, parse_js_1.parseRelativeDate)(input);
|
|
37
43
|
if (relativeResult)
|
|
38
44
|
return relativeResult;
|
|
39
45
|
// Common absolute patterns
|
|
@@ -61,6 +67,9 @@ export function parseNaturalDate(input, options = {}) {
|
|
|
61
67
|
return parseMatchedPattern(match, referenceDate, defaultTime);
|
|
62
68
|
}
|
|
63
69
|
}
|
|
70
|
+
if (strict) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
64
73
|
// Try standard Date parsing as fallback
|
|
65
74
|
const standardDate = new Date(input);
|
|
66
75
|
if (!isNaN(standardDate.getTime())) {
|
|
@@ -81,7 +90,7 @@ export function parseNaturalDate(input, options = {}) {
|
|
|
81
90
|
* parseRelativePhrase('next week'); // 7 days from now
|
|
82
91
|
* ```
|
|
83
92
|
*/
|
|
84
|
-
|
|
93
|
+
function parseRelativePhrase(input, referenceDate = new Date()) {
|
|
85
94
|
const normalized = input.toLowerCase().trim();
|
|
86
95
|
// "in X units"
|
|
87
96
|
const inPattern = /^in\s+(\d+)\s+(millisecond|milliseconds|second|seconds|minute|minutes|hour|hours|day|days|week|weeks|month|months|year|years)$/;
|
|
@@ -89,7 +98,7 @@ export function parseRelativePhrase(input, referenceDate = new Date()) {
|
|
|
89
98
|
if (match) {
|
|
90
99
|
const amount = parseInt(match[1], 10);
|
|
91
100
|
const unit = normalizeUnit(match[2]);
|
|
92
|
-
return addTime(referenceDate, amount, unit);
|
|
101
|
+
return (0, calculate_js_1.addTime)(referenceDate, amount, unit);
|
|
93
102
|
}
|
|
94
103
|
// "X units ago"
|
|
95
104
|
const agoPattern = /^(\d+)\s+(millisecond|milliseconds|second|seconds|minute|minutes|hour|hours|day|days|week|weeks|month|months|year|years)\s+ago$/;
|
|
@@ -97,7 +106,7 @@ export function parseRelativePhrase(input, referenceDate = new Date()) {
|
|
|
97
106
|
if (match) {
|
|
98
107
|
const amount = parseInt(match[1], 10);
|
|
99
108
|
const unit = normalizeUnit(match[2]);
|
|
100
|
-
return addTime(referenceDate, -amount, unit);
|
|
109
|
+
return (0, calculate_js_1.addTime)(referenceDate, -amount, unit);
|
|
101
110
|
}
|
|
102
111
|
// "X units from now"
|
|
103
112
|
const fromNowPattern = /^(\d+)\s+(millisecond|milliseconds|second|seconds|minute|minutes|hour|hours|day|days|week|weeks|month|months|year|years)\s+from\s+now$/;
|
|
@@ -105,7 +114,7 @@ export function parseRelativePhrase(input, referenceDate = new Date()) {
|
|
|
105
114
|
if (match) {
|
|
106
115
|
const amount = parseInt(match[1], 10);
|
|
107
116
|
const unit = normalizeUnit(match[2]);
|
|
108
|
-
return addTime(referenceDate, amount, unit);
|
|
117
|
+
return (0, calculate_js_1.addTime)(referenceDate, amount, unit);
|
|
109
118
|
}
|
|
110
119
|
// Common shortcuts - use switch/case to properly use the referenceDate parameter
|
|
111
120
|
switch (normalized) {
|
|
@@ -117,21 +126,21 @@ export function parseRelativePhrase(input, referenceDate = new Date()) {
|
|
|
117
126
|
return d;
|
|
118
127
|
}
|
|
119
128
|
case 'tomorrow':
|
|
120
|
-
return addTime(referenceDate, 1, 'day');
|
|
129
|
+
return (0, calculate_js_1.addTime)(referenceDate, 1, 'day');
|
|
121
130
|
case 'yesterday':
|
|
122
|
-
return addTime(referenceDate, -1, 'day');
|
|
131
|
+
return (0, calculate_js_1.addTime)(referenceDate, -1, 'day');
|
|
123
132
|
case 'next week':
|
|
124
|
-
return addTime(referenceDate, 1, 'week');
|
|
133
|
+
return (0, calculate_js_1.addTime)(referenceDate, 1, 'week');
|
|
125
134
|
case 'last week':
|
|
126
|
-
return addTime(referenceDate, -1, 'week');
|
|
135
|
+
return (0, calculate_js_1.addTime)(referenceDate, -1, 'week');
|
|
127
136
|
case 'next month':
|
|
128
|
-
return addTime(referenceDate, 1, 'month');
|
|
137
|
+
return (0, calculate_js_1.addTime)(referenceDate, 1, 'month');
|
|
129
138
|
case 'last month':
|
|
130
|
-
return addTime(referenceDate, -1, 'month');
|
|
139
|
+
return (0, calculate_js_1.addTime)(referenceDate, -1, 'month');
|
|
131
140
|
case 'next year':
|
|
132
|
-
return addTime(referenceDate, 1, 'year');
|
|
141
|
+
return (0, calculate_js_1.addTime)(referenceDate, 1, 'year');
|
|
133
142
|
case 'last year':
|
|
134
|
-
return addTime(referenceDate, -1, 'year');
|
|
143
|
+
return (0, calculate_js_1.addTime)(referenceDate, -1, 'year');
|
|
135
144
|
default:
|
|
136
145
|
return null;
|
|
137
146
|
}
|
|
@@ -152,7 +161,7 @@ export function parseRelativePhrase(input, referenceDate = new Date()) {
|
|
|
152
161
|
* // ]
|
|
153
162
|
* ```
|
|
154
163
|
*/
|
|
155
|
-
|
|
164
|
+
function extractDatesFromText(text, options = {}) {
|
|
156
165
|
const { referenceDate = new Date() } = options;
|
|
157
166
|
const results = [];
|
|
158
167
|
// Patterns to match
|
|
@@ -182,7 +191,11 @@ export function extractDatesFromText(text, options = {}) {
|
|
|
182
191
|
continue;
|
|
183
192
|
processed.add(`${index}-${matchedText}`);
|
|
184
193
|
// Try to parse the matched text
|
|
185
|
-
const parsed = parseNaturalDate(matchedText, {
|
|
194
|
+
const parsed = parseNaturalDate(matchedText, {
|
|
195
|
+
referenceDate,
|
|
196
|
+
defaultTime: options.defaultTime,
|
|
197
|
+
strict: options.strict
|
|
198
|
+
});
|
|
186
199
|
if (parsed) {
|
|
187
200
|
results.push({
|
|
188
201
|
date: parsed,
|
|
@@ -209,7 +222,7 @@ export function extractDatesFromText(text, options = {}) {
|
|
|
209
222
|
* // [{ date: Date(last day of current month), confidence: 0.8, ... }]
|
|
210
223
|
* ```
|
|
211
224
|
*/
|
|
212
|
-
|
|
225
|
+
function suggestDateFromContext(context, options = {}) {
|
|
213
226
|
const { referenceDate = new Date() } = options;
|
|
214
227
|
const suggestions = [];
|
|
215
228
|
const normalized = context.toLowerCase();
|
|
@@ -284,16 +297,16 @@ function parseMatchedPattern(match, referenceDate, defaultTime) {
|
|
|
284
297
|
if (daysToAdd <= 0)
|
|
285
298
|
daysToAdd += 7;
|
|
286
299
|
}
|
|
287
|
-
return addTime(referenceDate, daysToAdd, 'day');
|
|
300
|
+
return (0, calculate_js_1.addTime)(referenceDate, daysToAdd, 'day');
|
|
288
301
|
}
|
|
289
302
|
// "in X units" pattern
|
|
290
303
|
if (match[1] && match[2]) {
|
|
291
304
|
const amount = parseInt(match[1], 10);
|
|
292
305
|
const unit = normalizeUnit(match[2]);
|
|
293
306
|
if (match[3] === 'ago') {
|
|
294
|
-
return addTime(referenceDate, -amount, unit);
|
|
307
|
+
return (0, calculate_js_1.addTime)(referenceDate, -amount, unit);
|
|
295
308
|
}
|
|
296
|
-
return addTime(referenceDate, amount, unit);
|
|
309
|
+
return (0, calculate_js_1.addTime)(referenceDate, amount, unit);
|
|
297
310
|
}
|
|
298
311
|
return null;
|
|
299
312
|
}
|
|
@@ -14,9 +14,7 @@ export interface NaturalParseOptions {
|
|
|
14
14
|
minute: number;
|
|
15
15
|
second?: number;
|
|
16
16
|
};
|
|
17
|
-
/**
|
|
18
|
-
locale?: string;
|
|
19
|
-
/** Whether to use strict parsing */
|
|
17
|
+
/** Whether to skip permissive fallback parsing */
|
|
20
18
|
strict?: boolean;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"naturalLanguage.d.ts","sourceRoot":"","sources":["../src/naturalLanguage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,sDAAsD;IACtD,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,
|
|
1
|
+
{"version":3,"file":"naturalLanguage.d.ts","sourceRoot":"","sources":["../src/naturalLanguage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,sDAAsD;IACtD,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,kDAAkD;IAClD,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,IAAI,EAAE,IAAI,CAAC;IACX,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IACjD,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,IAAI,GAAG,IAAI,CAkD9F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,GAAE,IAAiB,GAAG,IAAI,GAAG,IAAI,CA6DhG;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,aAAa,EAAE,CAsDjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,KAAK,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAkDzD"}
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Advanced date parsing utilities
|
|
3
4
|
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseDate = parseDate;
|
|
7
|
+
exports.parseRelativeDate = parseRelativeDate;
|
|
8
|
+
exports.parseTimeAgo = parseTimeAgo;
|
|
9
|
+
exports.parseCustomFormat = parseCustomFormat;
|
|
10
|
+
exports.parseManyFormats = parseManyFormats;
|
|
11
|
+
exports.parseISO8601Duration = parseISO8601Duration;
|
|
12
|
+
exports.parseISO8601DurationToMs = parseISO8601DurationToMs;
|
|
13
|
+
exports.parseTime = parseTime;
|
|
14
|
+
exports.guessDateFormat = guessDateFormat;
|
|
15
|
+
exports.parseAutoFormat = parseAutoFormat;
|
|
16
|
+
exports.parseRangeEndpoint = parseRangeEndpoint;
|
|
4
17
|
/**
|
|
5
18
|
* Parse various date formats intelligently
|
|
6
19
|
* @param input - date string, number, or Date object
|
|
7
20
|
*/
|
|
8
|
-
|
|
21
|
+
function parseDate(input) {
|
|
9
22
|
if (input instanceof Date) {
|
|
10
23
|
return isNaN(input.getTime()) ? null : input;
|
|
11
24
|
}
|
|
@@ -61,7 +74,7 @@ export function parseDate(input) {
|
|
|
61
74
|
* Parse relative date strings like "tomorrow", "next monday", "2 weeks ago"
|
|
62
75
|
* @param input - relative date string
|
|
63
76
|
*/
|
|
64
|
-
|
|
77
|
+
function parseRelativeDate(input) {
|
|
65
78
|
const now = new Date();
|
|
66
79
|
const lowercaseInput = input.toLowerCase().trim();
|
|
67
80
|
// Handle simple cases
|
|
@@ -105,7 +118,7 @@ export function parseRelativeDate(input) {
|
|
|
105
118
|
* Parse "time ago" strings like "5 minutes ago", "2 hours ago"
|
|
106
119
|
* @param input - time ago string
|
|
107
120
|
*/
|
|
108
|
-
|
|
121
|
+
function parseTimeAgo(input) {
|
|
109
122
|
const now = new Date();
|
|
110
123
|
const lowercaseInput = input.toLowerCase().trim();
|
|
111
124
|
// Handle simple cases
|
|
@@ -125,7 +138,7 @@ export function parseTimeAgo(input) {
|
|
|
125
138
|
* @param dateString - date string to parse
|
|
126
139
|
* @param format - format pattern (e.g., "YYYY-MM-DD", "DD/MM/YYYY")
|
|
127
140
|
*/
|
|
128
|
-
|
|
141
|
+
function parseCustomFormat(dateString, format) {
|
|
129
142
|
// Simple implementation for common patterns
|
|
130
143
|
const formatMap = {
|
|
131
144
|
'YYYY-MM-DD': /^(\d{4})-(\d{2})-(\d{2})$/,
|
|
@@ -176,7 +189,7 @@ export function parseCustomFormat(dateString, format) {
|
|
|
176
189
|
* @param dateString - date string to parse
|
|
177
190
|
* @param formats - array of format patterns to try
|
|
178
191
|
*/
|
|
179
|
-
|
|
192
|
+
function parseManyFormats(dateString, formats) {
|
|
180
193
|
for (const format of formats) {
|
|
181
194
|
const result = parseCustomFormat(dateString, format);
|
|
182
195
|
if (result)
|
|
@@ -220,7 +233,7 @@ function subtractTimeUnits(date, amount, unit) {
|
|
|
220
233
|
* @param duration - ISO 8601 duration string
|
|
221
234
|
* @returns object with parsed components
|
|
222
235
|
*/
|
|
223
|
-
|
|
236
|
+
function parseISO8601Duration(duration) {
|
|
224
237
|
// ISO 8601 duration format: P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
|
|
225
238
|
const result = {
|
|
226
239
|
years: 0,
|
|
@@ -265,7 +278,7 @@ export function parseISO8601Duration(duration) {
|
|
|
265
278
|
* Convert ISO 8601 duration to milliseconds (approximate for months/years)
|
|
266
279
|
* @param duration - ISO 8601 duration string
|
|
267
280
|
*/
|
|
268
|
-
|
|
281
|
+
function parseISO8601DurationToMs(duration) {
|
|
269
282
|
const parsed = parseISO8601Duration(duration);
|
|
270
283
|
if (!parsed)
|
|
271
284
|
return null;
|
|
@@ -289,7 +302,7 @@ export function parseISO8601DurationToMs(duration) {
|
|
|
289
302
|
* @param timeString - time string to parse
|
|
290
303
|
* @returns object with hours, minutes, seconds, or null if invalid
|
|
291
304
|
*/
|
|
292
|
-
|
|
305
|
+
function parseTime(timeString) {
|
|
293
306
|
const normalized = timeString.trim();
|
|
294
307
|
// 24-hour format: HH:MM or HH:MM:SS
|
|
295
308
|
const match24 = normalized.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/);
|
|
@@ -328,7 +341,7 @@ export function parseTime(timeString) {
|
|
|
328
341
|
* @param dateString - date string to analyze
|
|
329
342
|
* @returns detected format pattern or null
|
|
330
343
|
*/
|
|
331
|
-
|
|
344
|
+
function guessDateFormat(dateString) {
|
|
332
345
|
const normalized = dateString.trim();
|
|
333
346
|
// YYYY-MM-DD
|
|
334
347
|
if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
|
|
@@ -367,7 +380,7 @@ export function guessDateFormat(dateString) {
|
|
|
367
380
|
* Parse a date string using auto-detected format
|
|
368
381
|
* @param dateString - date string to parse
|
|
369
382
|
*/
|
|
370
|
-
|
|
383
|
+
function parseAutoFormat(dateString) {
|
|
371
384
|
const format = guessDateFormat(dateString);
|
|
372
385
|
if (!format) {
|
|
373
386
|
return parseDate(dateString);
|
|
@@ -387,7 +400,7 @@ export function parseAutoFormat(dateString) {
|
|
|
387
400
|
* Parse a date from a natural language date range endpoint
|
|
388
401
|
* @param input - string like "end of month", "start of year", "beginning of week"
|
|
389
402
|
*/
|
|
390
|
-
|
|
403
|
+
function parseRangeEndpoint(input) {
|
|
391
404
|
const now = new Date();
|
|
392
405
|
const lowercaseInput = input.toLowerCase().trim();
|
|
393
406
|
// Start/beginning of period
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Async time utilities for delays, timeouts, and performance
|
|
3
4
|
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Stopwatch = void 0;
|
|
7
|
+
exports.sleep = sleep;
|
|
8
|
+
exports.timeout = timeout;
|
|
9
|
+
exports.debounce = debounce;
|
|
10
|
+
exports.throttle = throttle;
|
|
11
|
+
exports.retry = retry;
|
|
12
|
+
exports.createStopwatch = createStopwatch;
|
|
13
|
+
exports.measureTime = measureTime;
|
|
14
|
+
exports.measureAsync = measureAsync;
|
|
15
|
+
exports.benchmark = benchmark;
|
|
4
16
|
/**
|
|
5
17
|
* Sleep for a specified number of milliseconds
|
|
6
18
|
* @param ms - milliseconds to sleep
|
|
7
19
|
*/
|
|
8
|
-
|
|
20
|
+
function sleep(ms) {
|
|
9
21
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
10
22
|
}
|
|
11
23
|
/**
|
|
@@ -14,7 +26,7 @@ export function sleep(ms) {
|
|
|
14
26
|
* @param ms - timeout in milliseconds
|
|
15
27
|
* @param timeoutMessage - optional timeout error message
|
|
16
28
|
*/
|
|
17
|
-
|
|
29
|
+
function timeout(promise, ms, timeoutMessage = 'Operation timed out') {
|
|
18
30
|
return Promise.race([
|
|
19
31
|
promise,
|
|
20
32
|
new Promise((_, reject) => setTimeout(() => reject(new Error(timeoutMessage)), ms))
|
|
@@ -25,7 +37,7 @@ export function timeout(promise, ms, timeoutMessage = 'Operation timed out') {
|
|
|
25
37
|
* @param fn - function to debounce
|
|
26
38
|
* @param delay - delay in milliseconds
|
|
27
39
|
*/
|
|
28
|
-
|
|
40
|
+
function debounce(fn, delay) {
|
|
29
41
|
let timeoutId;
|
|
30
42
|
return (...args) => {
|
|
31
43
|
clearTimeout(timeoutId);
|
|
@@ -37,7 +49,7 @@ export function debounce(fn, delay) {
|
|
|
37
49
|
* @param fn - function to throttle
|
|
38
50
|
* @param delay - delay in milliseconds
|
|
39
51
|
*/
|
|
40
|
-
|
|
52
|
+
function throttle(fn, delay) {
|
|
41
53
|
let lastCall = 0;
|
|
42
54
|
return (...args) => {
|
|
43
55
|
const now = Date.now();
|
|
@@ -54,7 +66,7 @@ export function throttle(fn, delay) {
|
|
|
54
66
|
* @param baseDelay - base delay in milliseconds
|
|
55
67
|
* @param maxDelay - maximum delay in milliseconds
|
|
56
68
|
*/
|
|
57
|
-
|
|
69
|
+
async function retry(fn, maxAttempts = 3, baseDelay = 1000, maxDelay = 10000) {
|
|
58
70
|
let lastError;
|
|
59
71
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
60
72
|
try {
|
|
@@ -75,7 +87,7 @@ export async function retry(fn, maxAttempts = 3, baseDelay = 1000, maxDelay = 10
|
|
|
75
87
|
/**
|
|
76
88
|
* Stopwatch for measuring elapsed time
|
|
77
89
|
*/
|
|
78
|
-
|
|
90
|
+
class Stopwatch {
|
|
79
91
|
constructor() {
|
|
80
92
|
this.startTime = null;
|
|
81
93
|
this.endTime = null;
|
|
@@ -167,10 +179,11 @@ export class Stopwatch {
|
|
|
167
179
|
return this.pauseStart !== null;
|
|
168
180
|
}
|
|
169
181
|
}
|
|
182
|
+
exports.Stopwatch = Stopwatch;
|
|
170
183
|
/**
|
|
171
184
|
* Create a new stopwatch instance
|
|
172
185
|
*/
|
|
173
|
-
|
|
186
|
+
function createStopwatch() {
|
|
174
187
|
return new Stopwatch();
|
|
175
188
|
}
|
|
176
189
|
/**
|
|
@@ -178,7 +191,7 @@ export function createStopwatch() {
|
|
|
178
191
|
* @param fn - function to measure
|
|
179
192
|
* @returns tuple of [result, elapsed time in ms]
|
|
180
193
|
*/
|
|
181
|
-
|
|
194
|
+
function measureTime(fn) {
|
|
182
195
|
const start = performance.now();
|
|
183
196
|
const result = fn();
|
|
184
197
|
const elapsed = performance.now() - start;
|
|
@@ -189,7 +202,7 @@ export function measureTime(fn) {
|
|
|
189
202
|
* @param fn - async function to measure
|
|
190
203
|
* @returns promise that resolves to tuple of [result, elapsed time in ms]
|
|
191
204
|
*/
|
|
192
|
-
|
|
205
|
+
async function measureAsync(fn) {
|
|
193
206
|
const start = performance.now();
|
|
194
207
|
const result = await fn();
|
|
195
208
|
const elapsed = performance.now() - start;
|
|
@@ -200,7 +213,7 @@ export async function measureAsync(fn) {
|
|
|
200
213
|
* @param fn - function to benchmark
|
|
201
214
|
* @param iterations - number of iterations to run
|
|
202
215
|
*/
|
|
203
|
-
|
|
216
|
+
function benchmark(fn, iterations = 1000) {
|
|
204
217
|
const times = [];
|
|
205
218
|
for (let i = 0; i < iterations; i++) {
|
|
206
219
|
const [, elapsed] = measureTime(fn);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Plugin system for extending ChainedDate with custom methods
|
|
3
4
|
*
|
|
@@ -19,38 +20,26 @@
|
|
|
19
20
|
* chain(new Date()).nextMonday().format('YYYY-MM-DD');
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.extend = extend;
|
|
25
|
+
exports.uninstall = uninstall;
|
|
26
|
+
exports.getRegisteredPlugins = getRegisteredPlugins;
|
|
27
|
+
exports.getPluginMethods = getPluginMethods;
|
|
28
|
+
exports.isPluginRegistered = isPluginRegistered;
|
|
29
|
+
const chain_js_1 = require("./chain.cjs");
|
|
25
30
|
/**
|
|
26
|
-
* Get ChainedDate class
|
|
31
|
+
* Get ChainedDate class for prototype mutation.
|
|
32
|
+
* Importing `plugins` now brings in `chain` directly, so the class is available
|
|
33
|
+
* without a hidden global handshake.
|
|
27
34
|
*/
|
|
28
35
|
function getChainedDate() {
|
|
29
|
-
if (!
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
// Try ESM import path first
|
|
33
|
-
ChainedDateConstructor = globalThis.__chainedDateClass;
|
|
34
|
-
if (!ChainedDateConstructor) {
|
|
35
|
-
// Fallback: The class will be set by chain.js when it loads
|
|
36
|
-
throw new Error('ChainedDate not yet loaded. Import chain.js before using plugins.');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
throw new Error('ChainedDate class not available. Ensure chain.js is imported before registering plugins.');
|
|
41
|
-
}
|
|
36
|
+
if (!chain_js_1.ChainedDate) {
|
|
37
|
+
throw new Error('ChainedDate export is not available yet. Import chain.js before registering plugins.');
|
|
42
38
|
}
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Initialize the plugin system with ChainedDate class
|
|
47
|
-
* This is called automatically when chain.js is imported
|
|
48
|
-
* @internal
|
|
49
|
-
*/
|
|
50
|
-
export function __initPluginSystem(ChainedDateClass) {
|
|
51
|
-
ChainedDateConstructor = ChainedDateClass;
|
|
39
|
+
return chain_js_1.ChainedDate;
|
|
52
40
|
}
|
|
53
41
|
const registry = {};
|
|
42
|
+
const methodStates = {};
|
|
54
43
|
/**
|
|
55
44
|
* Extend ChainedDate with custom methods
|
|
56
45
|
*
|
|
@@ -76,27 +65,27 @@ const registry = {};
|
|
|
76
65
|
* chain(new Date()).addBusinessDays(5);
|
|
77
66
|
* ```
|
|
78
67
|
*/
|
|
79
|
-
|
|
68
|
+
function extend(pluginName, methods) {
|
|
80
69
|
if (registry[pluginName]) {
|
|
81
70
|
throw new Error(`Plugin "${pluginName}" is already registered. Use a different name or uninstall first.`);
|
|
82
71
|
}
|
|
83
|
-
// Get ChainedDate class and save original methods before overwriting
|
|
84
72
|
const ChainedDateClass = getChainedDate();
|
|
85
|
-
const originalMethods = new Map();
|
|
86
73
|
Object.entries(methods).forEach(([methodName, fn]) => {
|
|
87
|
-
|
|
74
|
+
const current = ChainedDateClass.prototype[methodName];
|
|
75
|
+
if (!methodStates[methodName]) {
|
|
76
|
+
methodStates[methodName] = {
|
|
77
|
+
original: typeof current === 'function' ? current : undefined,
|
|
78
|
+
owners: []
|
|
79
|
+
};
|
|
80
|
+
}
|
|
88
81
|
if (methodName in ChainedDateClass.prototype) {
|
|
89
|
-
const original = ChainedDateClass.prototype[methodName];
|
|
90
|
-
if (typeof original === 'function') {
|
|
91
|
-
originalMethods.set(methodName, original);
|
|
92
|
-
}
|
|
93
82
|
console.warn(`Method "${methodName}" already exists on ChainedDate and will be overwritten`);
|
|
94
83
|
}
|
|
84
|
+
methodStates[methodName].owners.push(pluginName);
|
|
95
85
|
// Add the plugin method
|
|
96
86
|
ChainedDateClass.prototype[methodName] = fn;
|
|
97
87
|
});
|
|
98
|
-
|
|
99
|
-
registry[pluginName] = { plugin: methods, originalMethods };
|
|
88
|
+
registry[pluginName] = { plugin: methods };
|
|
100
89
|
}
|
|
101
90
|
/**
|
|
102
91
|
* Remove a plugin and its methods from ChainedDate
|
|
@@ -108,25 +97,37 @@ export function extend(pluginName, methods) {
|
|
|
108
97
|
* uninstall('businessDays');
|
|
109
98
|
* ```
|
|
110
99
|
*/
|
|
111
|
-
|
|
100
|
+
function uninstall(pluginName) {
|
|
112
101
|
const entry = registry[pluginName];
|
|
113
102
|
if (!entry) {
|
|
114
103
|
throw new Error(`Plugin "${pluginName}" is not registered`);
|
|
115
104
|
}
|
|
116
|
-
// Get ChainedDate class and restore/remove methods
|
|
117
105
|
const ChainedDateClass = getChainedDate();
|
|
118
106
|
Object.keys(entry.plugin).forEach((methodName) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
107
|
+
const state = methodStates[methodName];
|
|
108
|
+
if (!state) {
|
|
109
|
+
delete ChainedDateClass.prototype[methodName];
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
state.owners = state.owners.filter((owner) => owner !== pluginName);
|
|
113
|
+
const nextOwner = state.owners[state.owners.length - 1];
|
|
114
|
+
if (nextOwner) {
|
|
115
|
+
const nextPlugin = registry[nextOwner];
|
|
116
|
+
if (nextPlugin && methodName in nextPlugin.plugin) {
|
|
117
|
+
ChainedDateClass.prototype[methodName] = nextPlugin.plugin[methodName];
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
delete ChainedDateClass.prototype[methodName];
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (state.original) {
|
|
124
|
+
ChainedDateClass.prototype[methodName] = state.original;
|
|
123
125
|
}
|
|
124
126
|
else {
|
|
125
|
-
// Otherwise, delete the method entirely
|
|
126
127
|
delete ChainedDateClass.prototype[methodName];
|
|
127
128
|
}
|
|
129
|
+
delete methodStates[methodName];
|
|
128
130
|
});
|
|
129
|
-
// Remove from registry
|
|
130
131
|
delete registry[pluginName];
|
|
131
132
|
}
|
|
132
133
|
/**
|
|
@@ -139,7 +140,7 @@ export function uninstall(pluginName) {
|
|
|
139
140
|
* getRegisteredPlugins(); // ['businessDays', 'myPlugin']
|
|
140
141
|
* ```
|
|
141
142
|
*/
|
|
142
|
-
|
|
143
|
+
function getRegisteredPlugins() {
|
|
143
144
|
return Object.keys(registry);
|
|
144
145
|
}
|
|
145
146
|
/**
|
|
@@ -153,7 +154,7 @@ export function getRegisteredPlugins() {
|
|
|
153
154
|
* getPluginMethods('businessDays'); // ['addBusinessDays', 'subtractBusinessDays']
|
|
154
155
|
* ```
|
|
155
156
|
*/
|
|
156
|
-
|
|
157
|
+
function getPluginMethods(pluginName) {
|
|
157
158
|
const entry = registry[pluginName];
|
|
158
159
|
return entry ? Object.keys(entry.plugin) : [];
|
|
159
160
|
}
|
|
@@ -168,6 +169,6 @@ export function getPluginMethods(pluginName) {
|
|
|
168
169
|
* isPluginRegistered('businessDays'); // true
|
|
169
170
|
* ```
|
|
170
171
|
*/
|
|
171
|
-
|
|
172
|
+
function isPluginRegistered(pluginName) {
|
|
172
173
|
return pluginName in registry;
|
|
173
174
|
}
|
package/dist/plugins.d.ts
CHANGED
|
@@ -19,12 +19,6 @@
|
|
|
19
19
|
* chain(new Date()).nextMonday().format('YYYY-MM-DD');
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
/**
|
|
23
|
-
* Initialize the plugin system with ChainedDate class
|
|
24
|
-
* This is called automatically when chain.js is imported
|
|
25
|
-
* @internal
|
|
26
|
-
*/
|
|
27
|
-
export declare function __initPluginSystem(ChainedDateClass: any): void;
|
|
28
22
|
/**
|
|
29
23
|
* Plugin function type - methods receive ChainedDate instance as `this`
|
|
30
24
|
*/
|
package/dist/plugins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAgBH;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAAC;CACtC;AAoBD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAwBhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAqClD;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAG7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,iBAAiB;CAAG"}
|