@usertour/helpers 0.0.35 → 0.0.36

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.
@@ -2,27 +2,151 @@
2
2
 
3
3
  // src/conditions/time.ts
4
4
  var import_date_fns = require("date-fns");
5
- var evaluateTimeCondition = (rules) => {
5
+
6
+ // src/type-utils.ts
7
+ var nativeIsArray = Array.isArray;
8
+ var ObjProto = Object.prototype;
9
+ var objToString = ObjProto.toString;
10
+ var objHasOwn = ObjProto.hasOwnProperty;
11
+ var isUndefined = (x) => x === void 0;
12
+ var isString = (x) => {
13
+ return objToString.call(x) === "[object String]";
14
+ };
15
+ var isEmptyString = (x) => isString(x) && x.trim().length === 0;
16
+ var isNull = (x) => {
17
+ return x === null;
18
+ };
19
+ var isNullish = (x) => isUndefined(x) || isNull(x);
20
+
21
+ // src/conditions/time.ts
22
+ function isEmpty(value) {
23
+ return isNullish(value) || isEmptyString(value);
24
+ }
25
+ function hasRequiredFields(data, type) {
26
+ if (type === "start") {
27
+ return !isEmpty(data.startDate) && !isEmpty(data.startDateHour) && !isEmpty(data.startDateMinute);
28
+ }
29
+ return !isEmpty(data.endDate) && !isEmpty(data.endDateHour) && !isEmpty(data.endDateMinute);
30
+ }
31
+ function parseLegacyDate(dateStr) {
32
+ const [month, day, year] = dateStr.split("/");
33
+ if (!month || !day || !year) {
34
+ return null;
35
+ }
36
+ return {
37
+ month: Number.parseInt(month),
38
+ day: Number.parseInt(day),
39
+ year: Number.parseInt(year)
40
+ };
41
+ }
42
+ function createLegacyDateTime(data, type) {
43
+ const dateStr = type === "start" ? data.startDate : data.endDate;
44
+ const hourStr = type === "start" ? data.startDateHour : data.endDateHour;
45
+ const minuteStr = type === "start" ? data.startDateMinute : data.endDateMinute;
46
+ if (!dateStr || !hourStr || !minuteStr) {
47
+ return null;
48
+ }
49
+ const dateParts = parseLegacyDate(dateStr);
50
+ if (!dateParts) {
51
+ return null;
52
+ }
53
+ const dateTime = new Date(
54
+ dateParts.year,
55
+ dateParts.month - 1,
56
+ dateParts.day,
57
+ Number.parseInt(hourStr),
58
+ Number.parseInt(minuteStr),
59
+ 0
60
+ );
61
+ return (0, import_date_fns.isValid)(dateTime) ? dateTime : null;
62
+ }
63
+ function isTimeConditionDataV2(data) {
64
+ return data && ("startTime" in data || "endTime" in data);
65
+ }
66
+ function isTimeConditionDataLegacy(data) {
67
+ return data && ("startDate" in data || "startDateHour" in data);
68
+ }
69
+ function convertTimeConditionLegacyToV2(legacyData) {
6
70
  try {
7
- const { endDate, endDateHour, endDateMinute, startDate, startDateHour, startDateMinute } = rules.data || {};
8
- if (!startDate || !startDateHour || !startDateMinute) {
9
- return false;
71
+ if (!hasRequiredFields(legacyData, "start")) {
72
+ return null;
10
73
  }
11
- const startTimeString = `${startDate}T${startDateHour.padStart(2, "0")}:${startDateMinute.padStart(2, "0")}:00`;
12
- const startTime = (0, import_date_fns.parseISO)(startTimeString);
13
- if (!(0, import_date_fns.isValid)(startTime)) {
14
- return false;
74
+ const startDateTime = createLegacyDateTime(legacyData, "start");
75
+ if (!startDateTime) {
76
+ return null;
15
77
  }
16
- const now = /* @__PURE__ */ new Date();
17
- if (!endDate || !endDateHour || !endDateMinute) {
18
- return (0, import_date_fns.isAfter)(now, startTime);
78
+ const result = {
79
+ startTime: startDateTime.toISOString()
80
+ };
81
+ if (hasRequiredFields(legacyData, "end")) {
82
+ const endDateTime = createLegacyDateTime(legacyData, "end");
83
+ if (endDateTime) {
84
+ result.endTime = endDateTime.toISOString();
85
+ }
19
86
  }
20
- const endTimeString = `${endDate}T${endDateHour.padStart(2, "0")}:${endDateMinute.padStart(2, "0")}:00`;
21
- const endTime = (0, import_date_fns.parseISO)(endTimeString);
22
- if (!(0, import_date_fns.isValid)(endTime)) {
23
- return false;
87
+ return result;
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+ function normalizeTimeConditionData(data) {
93
+ if (!data) {
94
+ return null;
95
+ }
96
+ if (isTimeConditionDataV2(data)) {
97
+ return data;
98
+ }
99
+ if (isTimeConditionDataLegacy(data)) {
100
+ return convertTimeConditionLegacyToV2(data);
101
+ }
102
+ return null;
103
+ }
104
+ function evaluateTimeConditionV2(data) {
105
+ if (!data.startTime) {
106
+ return false;
107
+ }
108
+ const startTime = (0, import_date_fns.parseISO)(data.startTime);
109
+ if (!(0, import_date_fns.isValid)(startTime)) {
110
+ return false;
111
+ }
112
+ const now = /* @__PURE__ */ new Date();
113
+ if (!data.endTime) {
114
+ return (0, import_date_fns.isAfter)(now, startTime);
115
+ }
116
+ const endTime = (0, import_date_fns.parseISO)(data.endTime);
117
+ if (!(0, import_date_fns.isValid)(endTime)) {
118
+ return false;
119
+ }
120
+ return (0, import_date_fns.isAfter)(now, startTime) && (0, import_date_fns.isBefore)(now, endTime);
121
+ }
122
+ function evaluateTimeConditionLegacy(data) {
123
+ if (!hasRequiredFields(data, "start")) {
124
+ return false;
125
+ }
126
+ const startDateTime = createLegacyDateTime(data, "start");
127
+ if (!startDateTime) {
128
+ return false;
129
+ }
130
+ const now = /* @__PURE__ */ new Date();
131
+ if (!hasRequiredFields(data, "end")) {
132
+ return (0, import_date_fns.isAfter)(now, startDateTime);
133
+ }
134
+ const endDateTime = createLegacyDateTime(data, "end");
135
+ if (!endDateTime) {
136
+ return false;
137
+ }
138
+ return (0, import_date_fns.isAfter)(now, startDateTime) && (0, import_date_fns.isBefore)(now, endDateTime);
139
+ }
140
+ var evaluateTimeCondition = (rules) => {
141
+ try {
142
+ const data = rules.data || {};
143
+ if (isTimeConditionDataV2(data)) {
144
+ return evaluateTimeConditionV2(data);
24
145
  }
25
- return (0, import_date_fns.isAfter)(now, startTime) && (0, import_date_fns.isBefore)(now, endTime);
146
+ if (isTimeConditionDataLegacy(data)) {
147
+ return evaluateTimeConditionLegacy(data);
148
+ }
149
+ return false;
26
150
  } catch {
27
151
  return false;
28
152
  }
@@ -30,7 +154,7 @@ var evaluateTimeCondition = (rules) => {
30
154
 
31
155
  // src/__tests__/time.test.ts
32
156
  describe("Time Condition Evaluation", () => {
33
- const mockNow = /* @__PURE__ */ new Date("2024-01-15T12:00:00Z");
157
+ const mockNow = new Date(2024, 0, 15, 12, 0, 0);
34
158
  beforeAll(() => {
35
159
  jest.useFakeTimers();
36
160
  jest.setSystemTime(mockNow);
@@ -38,36 +162,352 @@ describe("Time Condition Evaluation", () => {
38
162
  afterAll(() => {
39
163
  jest.useRealTimers();
40
164
  });
41
- test("should return true when current time is after start time and no end time", () => {
42
- const rules = {
43
- id: "condition-1",
44
- type: "condition",
45
- operators: "and",
46
- data: {
47
- startDate: "2024-01-15",
165
+ describe("Type Guards", () => {
166
+ test("isTimeConditionDataV2 should return true for new format", () => {
167
+ expect(isTimeConditionDataV2({ startTime: "2024-01-15T10:00:00Z" })).toBe(true);
168
+ expect(isTimeConditionDataV2({ endTime: "2024-01-15T14:00:00Z" })).toBe(true);
169
+ expect(
170
+ isTimeConditionDataV2({
171
+ startTime: "2024-01-15T10:00:00Z",
172
+ endTime: "2024-01-15T14:00:00Z"
173
+ })
174
+ ).toBe(true);
175
+ });
176
+ test("isTimeConditionDataV2 should return false for legacy format", () => {
177
+ expect(isTimeConditionDataV2({ startDate: "01/15/2024" })).toBe(false);
178
+ expect(isTimeConditionDataV2({})).toBe(false);
179
+ });
180
+ test("isTimeConditionDataLegacy should return true for legacy format", () => {
181
+ expect(isTimeConditionDataLegacy({ startDate: "01/15/2024" })).toBe(true);
182
+ expect(isTimeConditionDataLegacy({ startDateHour: "10" })).toBe(true);
183
+ expect(
184
+ isTimeConditionDataLegacy({
185
+ startDate: "01/15/2024",
186
+ startDateHour: "10",
187
+ startDateMinute: "00"
188
+ })
189
+ ).toBe(true);
190
+ });
191
+ test("isTimeConditionDataLegacy should return false for new format", () => {
192
+ expect(isTimeConditionDataLegacy({ startTime: "2024-01-15T10:00:00Z" })).toBe(false);
193
+ expect(isTimeConditionDataLegacy({})).toBe(false);
194
+ });
195
+ });
196
+ describe("Format Conversion", () => {
197
+ test("convertTimeConditionLegacyToV2 should convert valid legacy data", () => {
198
+ const legacyData = {
199
+ startDate: "01/15/2024",
200
+ startDateHour: "10",
201
+ startDateMinute: "00",
202
+ endDate: "01/15/2024",
203
+ endDateHour: "14",
204
+ endDateMinute: "00"
205
+ };
206
+ const result = convertTimeConditionLegacyToV2(legacyData);
207
+ expect(result).not.toBeNull();
208
+ expect(result == null ? void 0 : result.startTime).toBeDefined();
209
+ expect(result == null ? void 0 : result.endTime).toBeDefined();
210
+ expect(result == null ? void 0 : result.startTime).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
211
+ });
212
+ test("convertTimeConditionLegacyToV2 should convert legacy data without end time", () => {
213
+ const legacyData = {
214
+ startDate: "01/15/2024",
48
215
  startDateHour: "10",
49
216
  startDateMinute: "00",
50
217
  endDate: "",
51
218
  endDateHour: "",
52
219
  endDateMinute: ""
53
- }
54
- };
55
- expect(evaluateTimeCondition(rules)).toBe(true);
56
- });
57
- test("should return true when current time is within start and end time range", () => {
58
- const rules = {
59
- id: "condition-2",
60
- type: "condition",
61
- operators: "and",
62
- data: {
63
- startDate: "2024-01-15",
220
+ };
221
+ const result = convertTimeConditionLegacyToV2(legacyData);
222
+ expect(result).not.toBeNull();
223
+ expect(result == null ? void 0 : result.startTime).toBeDefined();
224
+ expect(result == null ? void 0 : result.endTime).toBeUndefined();
225
+ });
226
+ test("convertTimeConditionLegacyToV2 should return null for invalid data", () => {
227
+ expect(
228
+ convertTimeConditionLegacyToV2({
229
+ startDate: "",
230
+ startDateHour: "10",
231
+ startDateMinute: "00"
232
+ })
233
+ ).toBeNull();
234
+ expect(
235
+ convertTimeConditionLegacyToV2({
236
+ startDate: "01/15/2024",
237
+ startDateHour: "",
238
+ startDateMinute: "00"
239
+ })
240
+ ).toBeNull();
241
+ expect(
242
+ convertTimeConditionLegacyToV2({
243
+ startDate: "01/15/2024",
244
+ startDateHour: "10",
245
+ startDateMinute: ""
246
+ })
247
+ ).toBeNull();
248
+ });
249
+ test("normalizeTimeConditionData should return new format as-is", () => {
250
+ const newFormat = { startTime: "2024-01-15T10:00:00Z", endTime: "2024-01-15T14:00:00Z" };
251
+ expect(normalizeTimeConditionData(newFormat)).toEqual(newFormat);
252
+ });
253
+ test("normalizeTimeConditionData should convert legacy format", () => {
254
+ const legacyData = {
255
+ startDate: "01/15/2024",
64
256
  startDateHour: "10",
65
- startDateMinute: "00",
66
- endDate: "2024-01-15",
67
- endDateHour: "14",
68
- endDateMinute: "00"
69
- }
70
- };
71
- expect(evaluateTimeCondition(rules)).toBe(false);
257
+ startDateMinute: "00"
258
+ };
259
+ const result = normalizeTimeConditionData(legacyData);
260
+ expect(result).not.toBeNull();
261
+ expect(result == null ? void 0 : result.startTime).toBeDefined();
262
+ });
263
+ test("normalizeTimeConditionData should return null for invalid data", () => {
264
+ expect(normalizeTimeConditionData(null)).toBeNull();
265
+ expect(normalizeTimeConditionData(void 0)).toBeNull();
266
+ expect(normalizeTimeConditionData({})).toBeNull();
267
+ });
268
+ });
269
+ describe("Legacy Format Evaluation", () => {
270
+ test("should return true when current time is after start time and no end time", () => {
271
+ const rules = {
272
+ id: "condition-1",
273
+ type: "time",
274
+ data: {
275
+ startDate: "01/15/2024",
276
+ startDateHour: "10",
277
+ startDateMinute: "00",
278
+ endDate: "",
279
+ endDateHour: "",
280
+ endDateMinute: ""
281
+ }
282
+ };
283
+ expect(evaluateTimeCondition(rules)).toBe(true);
284
+ });
285
+ test("should return true when current time is within start and end time range", () => {
286
+ const rules = {
287
+ id: "condition-2",
288
+ type: "time",
289
+ data: {
290
+ startDate: "01/15/2024",
291
+ startDateHour: "10",
292
+ startDateMinute: "00",
293
+ endDate: "01/15/2024",
294
+ endDateHour: "14",
295
+ endDateMinute: "00"
296
+ }
297
+ };
298
+ expect(evaluateTimeCondition(rules)).toBe(true);
299
+ });
300
+ test("should return false when current time is before start time", () => {
301
+ const rules = {
302
+ id: "condition-3",
303
+ type: "time",
304
+ data: {
305
+ startDate: "01/15/2024",
306
+ startDateHour: "15",
307
+ startDateMinute: "00",
308
+ endDate: "",
309
+ endDateHour: "",
310
+ endDateMinute: ""
311
+ }
312
+ };
313
+ expect(evaluateTimeCondition(rules)).toBe(false);
314
+ });
315
+ test("should return false when current time is after end time", () => {
316
+ const rules = {
317
+ id: "condition-4",
318
+ type: "time",
319
+ data: {
320
+ startDate: "01/15/2024",
321
+ startDateHour: "10",
322
+ startDateMinute: "00",
323
+ endDate: "01/15/2024",
324
+ endDateHour: "11",
325
+ endDateMinute: "00"
326
+ }
327
+ };
328
+ expect(evaluateTimeCondition(rules)).toBe(false);
329
+ });
330
+ test("should return false when start date is missing", () => {
331
+ const rules = {
332
+ id: "condition-5",
333
+ type: "time",
334
+ data: {
335
+ startDate: "",
336
+ startDateHour: "10",
337
+ startDateMinute: "00"
338
+ }
339
+ };
340
+ expect(evaluateTimeCondition(rules)).toBe(false);
341
+ });
342
+ test("should return false when start hour is missing", () => {
343
+ const rules = {
344
+ id: "condition-6",
345
+ type: "time",
346
+ data: {
347
+ startDate: "01/15/2024",
348
+ startDateHour: "",
349
+ startDateMinute: "00"
350
+ }
351
+ };
352
+ expect(evaluateTimeCondition(rules)).toBe(false);
353
+ });
354
+ test("should handle empty endDate string", () => {
355
+ const rules = {
356
+ id: "condition-7",
357
+ type: "time",
358
+ data: {
359
+ startDate: "01/15/2024",
360
+ startDateHour: "10",
361
+ startDateMinute: "00",
362
+ endDate: "",
363
+ endDateHour: "00",
364
+ endDateMinute: "00"
365
+ }
366
+ };
367
+ expect(evaluateTimeCondition(rules)).toBe(true);
368
+ });
369
+ test("should handle cross-day time range", () => {
370
+ const crossDayTime = new Date(2024, 0, 15, 23, 0, 0);
371
+ jest.setSystemTime(crossDayTime);
372
+ const rules = {
373
+ id: "condition-8",
374
+ type: "time",
375
+ data: {
376
+ startDate: "01/15/2024",
377
+ startDateHour: "22",
378
+ startDateMinute: "00",
379
+ endDate: "01/16/2024",
380
+ endDateHour: "02",
381
+ endDateMinute: "00"
382
+ }
383
+ };
384
+ expect(evaluateTimeCondition(rules)).toBe(true);
385
+ jest.setSystemTime(mockNow);
386
+ });
387
+ });
388
+ describe("New Format (ISO 8601) Evaluation", () => {
389
+ test("should return true when current time is after start time and no end time", () => {
390
+ const startTime = new Date(2024, 0, 15, 10, 0, 0).toISOString();
391
+ const rules = {
392
+ id: "condition-v2-1",
393
+ type: "time",
394
+ data: {
395
+ startTime
396
+ }
397
+ };
398
+ expect(evaluateTimeCondition(rules)).toBe(true);
399
+ });
400
+ test("should return true when current time is within start and end time range", () => {
401
+ const startTime = new Date(2024, 0, 15, 10, 0, 0).toISOString();
402
+ const endTime = new Date(2024, 0, 15, 14, 0, 0).toISOString();
403
+ const rules = {
404
+ id: "condition-v2-2",
405
+ type: "time",
406
+ data: {
407
+ startTime,
408
+ endTime
409
+ }
410
+ };
411
+ expect(evaluateTimeCondition(rules)).toBe(true);
412
+ });
413
+ test("should return false when current time is before start time", () => {
414
+ const startTime = new Date(2024, 0, 15, 15, 0, 0).toISOString();
415
+ const rules = {
416
+ id: "condition-v2-3",
417
+ type: "time",
418
+ data: {
419
+ startTime
420
+ }
421
+ };
422
+ expect(evaluateTimeCondition(rules)).toBe(false);
423
+ });
424
+ test("should return false when current time is after end time", () => {
425
+ const startTime = new Date(2024, 0, 15, 10, 0, 0).toISOString();
426
+ const endTime = new Date(2024, 0, 15, 11, 0, 0).toISOString();
427
+ const rules = {
428
+ id: "condition-v2-4",
429
+ type: "time",
430
+ data: {
431
+ startTime,
432
+ endTime
433
+ }
434
+ };
435
+ expect(evaluateTimeCondition(rules)).toBe(false);
436
+ });
437
+ test("should return false when startTime is missing", () => {
438
+ const endTime = new Date(2024, 0, 15, 14, 0, 0).toISOString();
439
+ const rules = {
440
+ id: "condition-v2-5",
441
+ type: "time",
442
+ data: {
443
+ endTime
444
+ }
445
+ };
446
+ expect(evaluateTimeCondition(rules)).toBe(false);
447
+ });
448
+ test("should return false when startTime is invalid", () => {
449
+ const rules = {
450
+ id: "condition-v2-6",
451
+ type: "time",
452
+ data: {
453
+ startTime: "invalid-date"
454
+ }
455
+ };
456
+ expect(evaluateTimeCondition(rules)).toBe(false);
457
+ });
458
+ test("should handle timezone in ISO format", () => {
459
+ const rules = {
460
+ id: "condition-v2-7",
461
+ type: "time",
462
+ data: {
463
+ startTime: "2024-01-15T10:00:00+08:00",
464
+ endTime: "2024-01-15T14:00:00+08:00"
465
+ }
466
+ };
467
+ expect(typeof evaluateTimeCondition(rules)).toBe("boolean");
468
+ });
469
+ });
470
+ describe("Edge Cases", () => {
471
+ test("should return false for empty data", () => {
472
+ const rules = {
473
+ id: "condition-edge-1",
474
+ type: "time",
475
+ data: {}
476
+ };
477
+ expect(evaluateTimeCondition(rules)).toBe(false);
478
+ });
479
+ test("should return false for null data", () => {
480
+ const rules = {
481
+ id: "condition-edge-2",
482
+ type: "time",
483
+ data: null
484
+ };
485
+ expect(evaluateTimeCondition(rules)).toBe(false);
486
+ });
487
+ test("should return false for invalid date format in legacy", () => {
488
+ const rules = {
489
+ id: "condition-edge-3",
490
+ type: "time",
491
+ data: {
492
+ startDate: "invalid-date",
493
+ startDateHour: "10",
494
+ startDateMinute: "00"
495
+ }
496
+ };
497
+ expect(evaluateTimeCondition(rules)).toBe(false);
498
+ });
499
+ test("should handle invalid month/day in legacy format", () => {
500
+ const rules = {
501
+ id: "condition-edge-4",
502
+ type: "time",
503
+ data: {
504
+ startDate: "13/32/2024",
505
+ // Invalid month and day
506
+ startDateHour: "10",
507
+ startDateMinute: "00"
508
+ }
509
+ };
510
+ expect(evaluateTimeCondition(rules)).toBe(false);
511
+ });
72
512
  });
73
513
  });