@usertour/helpers 0.0.43 → 0.0.45

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.
@@ -14,46 +14,34 @@ var objToString = ObjProto.toString;
14
14
  var objHasOwn = ObjProto.hasOwnProperty;
15
15
 
16
16
  // src/attribute.ts
17
- var isValidYear = (date) => {
18
- const year = date.getFullYear();
19
- return year >= 1900 && year <= 2100;
20
- };
21
- var tryParseDate = (parser) => {
22
- try {
23
- const date = parser();
24
- return (0, import_date_fns.isValid)(date) && isValidYear(date);
25
- } catch {
17
+ var isValidISO8601 = (value) => {
18
+ if (typeof value !== "string") {
26
19
  return false;
27
20
  }
28
- };
29
- function isDateString(dateStr) {
30
- if (!Number.isNaN(Number(dateStr)) || dateStr.length < 10) {
21
+ const iso8601Pattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
22
+ if (!iso8601Pattern.test(value)) {
31
23
  return false;
32
24
  }
33
- const dateFormats = [
34
- "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
35
- "yyyy-MM-dd'T'HH:mm:ss'Z'",
36
- "yyyy-MM-dd'T'HH:mm:ss.SSS",
37
- "yyyy-MM-dd'T'HH:mm:ss",
38
- "yyyy-MM-dd",
39
- "MM/dd/yyyy",
40
- "dd/MM/yyyy",
41
- "yyyy/MM/dd",
42
- "MM-dd-yyyy",
43
- "dd-MM-yyyy"
44
- ];
45
- if (tryParseDate(() => (0, import_date_fns.parseISO)(dateStr))) {
46
- return true;
25
+ try {
26
+ const date = (0, import_date_fns.parseISO)(value);
27
+ if (!(0, import_date_fns.isValid)(date)) {
28
+ return false;
29
+ }
30
+ const isoString = date.toISOString();
31
+ const normalizedInput = value.replace(/\.\d{3}Z$/, "Z");
32
+ const normalizedIso = isoString.replace(/\.\d{3}Z$/, "Z");
33
+ return normalizedInput === normalizedIso || value === isoString;
34
+ } catch {
35
+ return false;
47
36
  }
48
- return dateFormats.some((format) => tryParseDate(() => (0, import_date_fns.parse)(dateStr, format, /* @__PURE__ */ new Date())));
49
- }
37
+ };
50
38
  var getAttributeType = (attribute) => {
51
39
  const t = typeof attribute;
52
40
  if (t === "number") {
53
41
  return import_types.BizAttributeTypes.Number;
54
42
  }
55
43
  if (t === "string") {
56
- if (isDateString(attribute)) {
44
+ if (isValidISO8601(attribute)) {
57
45
  return import_types.BizAttributeTypes.DateTime;
58
46
  }
59
47
  return import_types.BizAttributeTypes.String;
@@ -100,39 +88,45 @@ describe("getAttributeType", () => {
100
88
  expect(getAttributeType("123abc")).toBe(import_types2.BizAttributeTypes.String);
101
89
  });
102
90
  });
103
- describe("DateTime type", () => {
104
- test("should return DateTime for ISO 8601 format with time", () => {
91
+ describe("DateTime type - ISO 8601 UTC only", () => {
92
+ test("should return DateTime for ISO 8601 format with milliseconds and Z", () => {
105
93
  expect(getAttributeType("2024-12-11T16:00:00.000Z")).toBe(import_types2.BizAttributeTypes.DateTime);
106
94
  });
107
- test("should return DateTime for ISO 8601 format without milliseconds", () => {
95
+ test("should return DateTime for ISO 8601 format without milliseconds but with Z", () => {
108
96
  expect(getAttributeType("2024-12-11T16:00:00Z")).toBe(import_types2.BizAttributeTypes.DateTime);
109
97
  });
110
- test("should return DateTime for ISO 8601 format without timezone", () => {
111
- expect(getAttributeType("2024-12-11T16:00:00")).toBe(import_types2.BizAttributeTypes.DateTime);
98
+ test("should return DateTime for ISO 8601 format at midnight", () => {
99
+ expect(getAttributeType("2024-12-11T00:00:00.000Z")).toBe(import_types2.BizAttributeTypes.DateTime);
100
+ });
101
+ test("should return DateTime for ISO 8601 format at end of day", () => {
102
+ expect(getAttributeType("2024-12-11T23:59:59.999Z")).toBe(import_types2.BizAttributeTypes.DateTime);
103
+ });
104
+ test("should return String for ISO 8601 format without timezone (no Z)", () => {
105
+ expect(getAttributeType("2024-12-11T16:00:00")).toBe(import_types2.BizAttributeTypes.String);
112
106
  });
113
- test("should return DateTime for ISO 8601 date only", () => {
114
- expect(getAttributeType("2024-12-11")).toBe(import_types2.BizAttributeTypes.DateTime);
107
+ test("should return String for ISO 8601 date only (no T and Z)", () => {
108
+ expect(getAttributeType("2024-12-11")).toBe(import_types2.BizAttributeTypes.String);
115
109
  });
116
- test("should return DateTime for MM/DD/YYYY format", () => {
117
- expect(getAttributeType("12/12/2024")).toBe(import_types2.BizAttributeTypes.DateTime);
110
+ test("should return String for MM/DD/YYYY format", () => {
111
+ expect(getAttributeType("12/12/2024")).toBe(import_types2.BizAttributeTypes.String);
118
112
  });
119
- test("should return DateTime for YYYY/MM/DD format", () => {
120
- expect(getAttributeType("2024/12/11")).toBe(import_types2.BizAttributeTypes.DateTime);
113
+ test("should return String for YYYY/MM/DD format", () => {
114
+ expect(getAttributeType("2024/12/11")).toBe(import_types2.BizAttributeTypes.String);
121
115
  });
122
- test("should return DateTime for MM-DD-YYYY format", () => {
123
- expect(getAttributeType("12-12-2024")).toBe(import_types2.BizAttributeTypes.DateTime);
116
+ test("should return String for MM-DD-YYYY format", () => {
117
+ expect(getAttributeType("12-12-2024")).toBe(import_types2.BizAttributeTypes.String);
124
118
  });
125
- test("should return DateTime for DD-MM-YYYY format", () => {
126
- expect(getAttributeType("11-12-2024")).toBe(import_types2.BizAttributeTypes.DateTime);
119
+ test("should return String for DD-MM-YYYY format", () => {
120
+ expect(getAttributeType("11-12-2024")).toBe(import_types2.BizAttributeTypes.String);
127
121
  });
128
- test("should return String for invalid date string", () => {
129
- expect(getAttributeType("2024-13-45")).toBe(import_types2.BizAttributeTypes.String);
122
+ test("should return String for invalid ISO 8601 format", () => {
123
+ expect(getAttributeType("2024-13-45T00:00:00.000Z")).toBe(import_types2.BizAttributeTypes.String);
130
124
  });
131
- test("should return String for date string with invalid year (< 1900)", () => {
132
- expect(getAttributeType("1899-12-11")).toBe(import_types2.BizAttributeTypes.String);
125
+ test("should return String for ISO 8601 with timezone offset (not UTC)", () => {
126
+ expect(getAttributeType("2024-12-11T16:00:00.000+08:00")).toBe(import_types2.BizAttributeTypes.String);
133
127
  });
134
- test("should return String for date string with invalid year (> 2100)", () => {
135
- expect(getAttributeType("2101-12-11")).toBe(import_types2.BizAttributeTypes.String);
128
+ test("should return String for ISO 8601 with lowercase z", () => {
129
+ expect(getAttributeType("2024-12-11T16:00:00.000z")).toBe(import_types2.BizAttributeTypes.String);
136
130
  });
137
131
  });
138
132
  describe("Boolean type", () => {
@@ -182,8 +176,8 @@ describe("getAttributeType", () => {
182
176
  test("should return String for string that is exactly 9 characters", () => {
183
177
  expect(getAttributeType("123456789")).toBe(import_types2.BizAttributeTypes.String);
184
178
  });
185
- test("should return DateTime for string that is exactly 10 characters and valid date", () => {
186
- expect(getAttributeType("2024-12-11")).toBe(import_types2.BizAttributeTypes.DateTime);
179
+ test("should return String for string that is exactly 10 characters but not ISO 8601 UTC", () => {
180
+ expect(getAttributeType("2024-12-11")).toBe(import_types2.BizAttributeTypes.String);
187
181
  });
188
182
  test("should return String for string that contains date-like pattern but invalid", () => {
189
183
  expect(getAttributeType("2024-99-99")).toBe(import_types2.BizAttributeTypes.String);
@@ -193,3 +187,104 @@ describe("getAttributeType", () => {
193
187
  });
194
188
  });
195
189
  });
190
+ describe("isValidISO8601", () => {
191
+ describe("Valid ISO 8601 UTC formats", () => {
192
+ test("should return true for ISO 8601 with milliseconds and Z", () => {
193
+ expect(isValidISO8601("2024-12-11T16:00:00.000Z")).toBe(true);
194
+ });
195
+ test("should return true for ISO 8601 without milliseconds but with Z", () => {
196
+ expect(isValidISO8601("2024-12-11T16:00:00Z")).toBe(true);
197
+ });
198
+ test("should return true for ISO 8601 at midnight", () => {
199
+ expect(isValidISO8601("2024-12-11T00:00:00.000Z")).toBe(true);
200
+ });
201
+ test("should return true for ISO 8601 at end of day", () => {
202
+ expect(isValidISO8601("2024-12-11T23:59:59.999Z")).toBe(true);
203
+ });
204
+ test("should return true for ISO 8601 with single digit month and day", () => {
205
+ expect(isValidISO8601("2024-01-01T00:00:00.000Z")).toBe(true);
206
+ });
207
+ test("should return true for ISO 8601 in year 1900", () => {
208
+ expect(isValidISO8601("1900-01-01T00:00:00.000Z")).toBe(true);
209
+ });
210
+ test("should return true for ISO 8601 in year 2100", () => {
211
+ expect(isValidISO8601("2100-12-31T23:59:59.999Z")).toBe(true);
212
+ });
213
+ test("should return true for ISO 8601 with year before 1900", () => {
214
+ expect(isValidISO8601("1800-01-01T00:00:00.000Z")).toBe(true);
215
+ });
216
+ test("should return true for ISO 8601 with year after 2100", () => {
217
+ expect(isValidISO8601("2200-01-01T00:00:00.000Z")).toBe(true);
218
+ });
219
+ });
220
+ describe("Invalid ISO 8601 UTC formats", () => {
221
+ test("should return false for non-string values", () => {
222
+ expect(isValidISO8601(null)).toBe(false);
223
+ expect(isValidISO8601(void 0)).toBe(false);
224
+ expect(isValidISO8601(123)).toBe(false);
225
+ expect(isValidISO8601(/* @__PURE__ */ new Date())).toBe(false);
226
+ expect(isValidISO8601({})).toBe(false);
227
+ });
228
+ test("should return false for ISO 8601 without T separator", () => {
229
+ expect(isValidISO8601("2024-12-11 16:00:00.000Z")).toBe(false);
230
+ expect(isValidISO8601("2024-12-11")).toBe(false);
231
+ });
232
+ test("should return false for ISO 8601 without Z (UTC indicator)", () => {
233
+ expect(isValidISO8601("2024-12-11T16:00:00.000")).toBe(false);
234
+ expect(isValidISO8601("2024-12-11T16:00:00")).toBe(false);
235
+ });
236
+ test("should return false for ISO 8601 with timezone offset (including +00:00)", () => {
237
+ expect(isValidISO8601("2024-12-11T16:00:00.000+08:00")).toBe(false);
238
+ expect(isValidISO8601("2024-12-11T16:00:00.000-05:00")).toBe(false);
239
+ expect(isValidISO8601("2024-12-11T16:00:00.000+01:00")).toBe(false);
240
+ expect(isValidISO8601("2024-12-11T16:00:00.000-01:00")).toBe(false);
241
+ expect(isValidISO8601("2024-12-11T16:00:00.000+00:00")).toBe(false);
242
+ expect(isValidISO8601("2024-12-11T16:00:00.000-00:00")).toBe(false);
243
+ expect(isValidISO8601("2024-12-11T16:00:00+00:00")).toBe(false);
244
+ });
245
+ test("should return false for ISO 8601 with lowercase z", () => {
246
+ expect(isValidISO8601("2024-12-11T16:00:00.000z")).toBe(false);
247
+ });
248
+ test("should return false for invalid date values", () => {
249
+ expect(isValidISO8601("2024-13-45T00:00:00.000Z")).toBe(false);
250
+ expect(isValidISO8601("2024-02-30T00:00:00.000Z")).toBe(false);
251
+ expect(isValidISO8601("2024-00-00T00:00:00.000Z")).toBe(false);
252
+ });
253
+ test("should return false for other date formats", () => {
254
+ expect(isValidISO8601("12/12/2024")).toBe(false);
255
+ expect(isValidISO8601("2024/12/11")).toBe(false);
256
+ expect(isValidISO8601("12-12-2024")).toBe(false);
257
+ expect(isValidISO8601("11-12-2024")).toBe(false);
258
+ });
259
+ test("should return false for malformed ISO 8601 strings", () => {
260
+ expect(isValidISO8601("2024-12-11T")).toBe(false);
261
+ expect(isValidISO8601("T16:00:00.000Z")).toBe(false);
262
+ expect(isValidISO8601("2024-12-11T16:00:00.Z")).toBe(false);
263
+ expect(isValidISO8601("2024-12-11T16:00.000Z")).toBe(false);
264
+ expect(isValidISO8601("2024-12-11T16:00:00.000")).toBe(false);
265
+ });
266
+ test("should return false for empty string", () => {
267
+ expect(isValidISO8601("")).toBe(false);
268
+ });
269
+ test("should return false for string that looks like ISO 8601 but has extra characters", () => {
270
+ expect(isValidISO8601("2024-12-11T16:00:00.000Z extra")).toBe(false);
271
+ expect(isValidISO8601("prefix 2024-12-11T16:00:00.000Z")).toBe(false);
272
+ });
273
+ });
274
+ describe("Edge cases", () => {
275
+ test("should handle leap year correctly", () => {
276
+ expect(isValidISO8601("2024-02-29T00:00:00.000Z")).toBe(true);
277
+ expect(isValidISO8601("2023-02-29T00:00:00.000Z")).toBe(false);
278
+ });
279
+ test("should handle different time values correctly", () => {
280
+ expect(isValidISO8601("2024-12-11T12:30:45.123Z")).toBe(true);
281
+ expect(isValidISO8601("2024-12-11T00:00:00.000Z")).toBe(true);
282
+ expect(isValidISO8601("2024-12-11T23:59:59.999Z")).toBe(true);
283
+ });
284
+ test("should handle milliseconds correctly", () => {
285
+ expect(isValidISO8601("2024-12-11T16:00:00.000Z")).toBe(true);
286
+ expect(isValidISO8601("2024-12-11T16:00:00.999Z")).toBe(true);
287
+ expect(isValidISO8601("2024-12-11T16:00:00Z")).toBe(true);
288
+ });
289
+ });
290
+ });
@@ -1,6 +1,7 @@
1
1
  import {
2
- getAttributeType
3
- } from "../chunk-EEYZG4JJ.js";
2
+ getAttributeType,
3
+ isValidISO8601
4
+ } from "../chunk-R4R6MDTW.js";
4
5
  import "../chunk-GFH3VWOC.js";
5
6
  import "../chunk-XEO3YXBM.js";
6
7
 
@@ -38,39 +39,45 @@ describe("getAttributeType", () => {
38
39
  expect(getAttributeType("123abc")).toBe(BizAttributeTypes.String);
39
40
  });
40
41
  });
41
- describe("DateTime type", () => {
42
- test("should return DateTime for ISO 8601 format with time", () => {
42
+ describe("DateTime type - ISO 8601 UTC only", () => {
43
+ test("should return DateTime for ISO 8601 format with milliseconds and Z", () => {
43
44
  expect(getAttributeType("2024-12-11T16:00:00.000Z")).toBe(BizAttributeTypes.DateTime);
44
45
  });
45
- test("should return DateTime for ISO 8601 format without milliseconds", () => {
46
+ test("should return DateTime for ISO 8601 format without milliseconds but with Z", () => {
46
47
  expect(getAttributeType("2024-12-11T16:00:00Z")).toBe(BizAttributeTypes.DateTime);
47
48
  });
48
- test("should return DateTime for ISO 8601 format without timezone", () => {
49
- expect(getAttributeType("2024-12-11T16:00:00")).toBe(BizAttributeTypes.DateTime);
49
+ test("should return DateTime for ISO 8601 format at midnight", () => {
50
+ expect(getAttributeType("2024-12-11T00:00:00.000Z")).toBe(BizAttributeTypes.DateTime);
50
51
  });
51
- test("should return DateTime for ISO 8601 date only", () => {
52
- expect(getAttributeType("2024-12-11")).toBe(BizAttributeTypes.DateTime);
52
+ test("should return DateTime for ISO 8601 format at end of day", () => {
53
+ expect(getAttributeType("2024-12-11T23:59:59.999Z")).toBe(BizAttributeTypes.DateTime);
53
54
  });
54
- test("should return DateTime for MM/DD/YYYY format", () => {
55
- expect(getAttributeType("12/12/2024")).toBe(BizAttributeTypes.DateTime);
55
+ test("should return String for ISO 8601 format without timezone (no Z)", () => {
56
+ expect(getAttributeType("2024-12-11T16:00:00")).toBe(BizAttributeTypes.String);
56
57
  });
57
- test("should return DateTime for YYYY/MM/DD format", () => {
58
- expect(getAttributeType("2024/12/11")).toBe(BizAttributeTypes.DateTime);
58
+ test("should return String for ISO 8601 date only (no T and Z)", () => {
59
+ expect(getAttributeType("2024-12-11")).toBe(BizAttributeTypes.String);
59
60
  });
60
- test("should return DateTime for MM-DD-YYYY format", () => {
61
- expect(getAttributeType("12-12-2024")).toBe(BizAttributeTypes.DateTime);
61
+ test("should return String for MM/DD/YYYY format", () => {
62
+ expect(getAttributeType("12/12/2024")).toBe(BizAttributeTypes.String);
62
63
  });
63
- test("should return DateTime for DD-MM-YYYY format", () => {
64
- expect(getAttributeType("11-12-2024")).toBe(BizAttributeTypes.DateTime);
64
+ test("should return String for YYYY/MM/DD format", () => {
65
+ expect(getAttributeType("2024/12/11")).toBe(BizAttributeTypes.String);
65
66
  });
66
- test("should return String for invalid date string", () => {
67
- expect(getAttributeType("2024-13-45")).toBe(BizAttributeTypes.String);
67
+ test("should return String for MM-DD-YYYY format", () => {
68
+ expect(getAttributeType("12-12-2024")).toBe(BizAttributeTypes.String);
68
69
  });
69
- test("should return String for date string with invalid year (< 1900)", () => {
70
- expect(getAttributeType("1899-12-11")).toBe(BizAttributeTypes.String);
70
+ test("should return String for DD-MM-YYYY format", () => {
71
+ expect(getAttributeType("11-12-2024")).toBe(BizAttributeTypes.String);
71
72
  });
72
- test("should return String for date string with invalid year (> 2100)", () => {
73
- expect(getAttributeType("2101-12-11")).toBe(BizAttributeTypes.String);
73
+ test("should return String for invalid ISO 8601 format", () => {
74
+ expect(getAttributeType("2024-13-45T00:00:00.000Z")).toBe(BizAttributeTypes.String);
75
+ });
76
+ test("should return String for ISO 8601 with timezone offset (not UTC)", () => {
77
+ expect(getAttributeType("2024-12-11T16:00:00.000+08:00")).toBe(BizAttributeTypes.String);
78
+ });
79
+ test("should return String for ISO 8601 with lowercase z", () => {
80
+ expect(getAttributeType("2024-12-11T16:00:00.000z")).toBe(BizAttributeTypes.String);
74
81
  });
75
82
  });
76
83
  describe("Boolean type", () => {
@@ -120,8 +127,8 @@ describe("getAttributeType", () => {
120
127
  test("should return String for string that is exactly 9 characters", () => {
121
128
  expect(getAttributeType("123456789")).toBe(BizAttributeTypes.String);
122
129
  });
123
- test("should return DateTime for string that is exactly 10 characters and valid date", () => {
124
- expect(getAttributeType("2024-12-11")).toBe(BizAttributeTypes.DateTime);
130
+ test("should return String for string that is exactly 10 characters but not ISO 8601 UTC", () => {
131
+ expect(getAttributeType("2024-12-11")).toBe(BizAttributeTypes.String);
125
132
  });
126
133
  test("should return String for string that contains date-like pattern but invalid", () => {
127
134
  expect(getAttributeType("2024-99-99")).toBe(BizAttributeTypes.String);
@@ -131,3 +138,104 @@ describe("getAttributeType", () => {
131
138
  });
132
139
  });
133
140
  });
141
+ describe("isValidISO8601", () => {
142
+ describe("Valid ISO 8601 UTC formats", () => {
143
+ test("should return true for ISO 8601 with milliseconds and Z", () => {
144
+ expect(isValidISO8601("2024-12-11T16:00:00.000Z")).toBe(true);
145
+ });
146
+ test("should return true for ISO 8601 without milliseconds but with Z", () => {
147
+ expect(isValidISO8601("2024-12-11T16:00:00Z")).toBe(true);
148
+ });
149
+ test("should return true for ISO 8601 at midnight", () => {
150
+ expect(isValidISO8601("2024-12-11T00:00:00.000Z")).toBe(true);
151
+ });
152
+ test("should return true for ISO 8601 at end of day", () => {
153
+ expect(isValidISO8601("2024-12-11T23:59:59.999Z")).toBe(true);
154
+ });
155
+ test("should return true for ISO 8601 with single digit month and day", () => {
156
+ expect(isValidISO8601("2024-01-01T00:00:00.000Z")).toBe(true);
157
+ });
158
+ test("should return true for ISO 8601 in year 1900", () => {
159
+ expect(isValidISO8601("1900-01-01T00:00:00.000Z")).toBe(true);
160
+ });
161
+ test("should return true for ISO 8601 in year 2100", () => {
162
+ expect(isValidISO8601("2100-12-31T23:59:59.999Z")).toBe(true);
163
+ });
164
+ test("should return true for ISO 8601 with year before 1900", () => {
165
+ expect(isValidISO8601("1800-01-01T00:00:00.000Z")).toBe(true);
166
+ });
167
+ test("should return true for ISO 8601 with year after 2100", () => {
168
+ expect(isValidISO8601("2200-01-01T00:00:00.000Z")).toBe(true);
169
+ });
170
+ });
171
+ describe("Invalid ISO 8601 UTC formats", () => {
172
+ test("should return false for non-string values", () => {
173
+ expect(isValidISO8601(null)).toBe(false);
174
+ expect(isValidISO8601(void 0)).toBe(false);
175
+ expect(isValidISO8601(123)).toBe(false);
176
+ expect(isValidISO8601(/* @__PURE__ */ new Date())).toBe(false);
177
+ expect(isValidISO8601({})).toBe(false);
178
+ });
179
+ test("should return false for ISO 8601 without T separator", () => {
180
+ expect(isValidISO8601("2024-12-11 16:00:00.000Z")).toBe(false);
181
+ expect(isValidISO8601("2024-12-11")).toBe(false);
182
+ });
183
+ test("should return false for ISO 8601 without Z (UTC indicator)", () => {
184
+ expect(isValidISO8601("2024-12-11T16:00:00.000")).toBe(false);
185
+ expect(isValidISO8601("2024-12-11T16:00:00")).toBe(false);
186
+ });
187
+ test("should return false for ISO 8601 with timezone offset (including +00:00)", () => {
188
+ expect(isValidISO8601("2024-12-11T16:00:00.000+08:00")).toBe(false);
189
+ expect(isValidISO8601("2024-12-11T16:00:00.000-05:00")).toBe(false);
190
+ expect(isValidISO8601("2024-12-11T16:00:00.000+01:00")).toBe(false);
191
+ expect(isValidISO8601("2024-12-11T16:00:00.000-01:00")).toBe(false);
192
+ expect(isValidISO8601("2024-12-11T16:00:00.000+00:00")).toBe(false);
193
+ expect(isValidISO8601("2024-12-11T16:00:00.000-00:00")).toBe(false);
194
+ expect(isValidISO8601("2024-12-11T16:00:00+00:00")).toBe(false);
195
+ });
196
+ test("should return false for ISO 8601 with lowercase z", () => {
197
+ expect(isValidISO8601("2024-12-11T16:00:00.000z")).toBe(false);
198
+ });
199
+ test("should return false for invalid date values", () => {
200
+ expect(isValidISO8601("2024-13-45T00:00:00.000Z")).toBe(false);
201
+ expect(isValidISO8601("2024-02-30T00:00:00.000Z")).toBe(false);
202
+ expect(isValidISO8601("2024-00-00T00:00:00.000Z")).toBe(false);
203
+ });
204
+ test("should return false for other date formats", () => {
205
+ expect(isValidISO8601("12/12/2024")).toBe(false);
206
+ expect(isValidISO8601("2024/12/11")).toBe(false);
207
+ expect(isValidISO8601("12-12-2024")).toBe(false);
208
+ expect(isValidISO8601("11-12-2024")).toBe(false);
209
+ });
210
+ test("should return false for malformed ISO 8601 strings", () => {
211
+ expect(isValidISO8601("2024-12-11T")).toBe(false);
212
+ expect(isValidISO8601("T16:00:00.000Z")).toBe(false);
213
+ expect(isValidISO8601("2024-12-11T16:00:00.Z")).toBe(false);
214
+ expect(isValidISO8601("2024-12-11T16:00.000Z")).toBe(false);
215
+ expect(isValidISO8601("2024-12-11T16:00:00.000")).toBe(false);
216
+ });
217
+ test("should return false for empty string", () => {
218
+ expect(isValidISO8601("")).toBe(false);
219
+ });
220
+ test("should return false for string that looks like ISO 8601 but has extra characters", () => {
221
+ expect(isValidISO8601("2024-12-11T16:00:00.000Z extra")).toBe(false);
222
+ expect(isValidISO8601("prefix 2024-12-11T16:00:00.000Z")).toBe(false);
223
+ });
224
+ });
225
+ describe("Edge cases", () => {
226
+ test("should handle leap year correctly", () => {
227
+ expect(isValidISO8601("2024-02-29T00:00:00.000Z")).toBe(true);
228
+ expect(isValidISO8601("2023-02-29T00:00:00.000Z")).toBe(false);
229
+ });
230
+ test("should handle different time values correctly", () => {
231
+ expect(isValidISO8601("2024-12-11T12:30:45.123Z")).toBe(true);
232
+ expect(isValidISO8601("2024-12-11T00:00:00.000Z")).toBe(true);
233
+ expect(isValidISO8601("2024-12-11T23:59:59.999Z")).toBe(true);
234
+ });
235
+ test("should handle milliseconds correctly", () => {
236
+ expect(isValidISO8601("2024-12-11T16:00:00.000Z")).toBe(true);
237
+ expect(isValidISO8601("2024-12-11T16:00:00.999Z")).toBe(true);
238
+ expect(isValidISO8601("2024-12-11T16:00:00Z")).toBe(true);
239
+ });
240
+ });
241
+ });
@@ -321,6 +321,12 @@ describe("URL Condition Evaluation", () => {
321
321
  const excludes = [];
322
322
  expect(isMatchUrlPattern(url, includes, excludes)).toBe(true);
323
323
  });
324
+ test("should handle URL patterns with wildcard in nested path", () => {
325
+ const url = "http://localhost:3004/client-view/sites/SUPERCONCEPTS/funds/aaaa/queries";
326
+ const includes = ["/client-view/sites/SUPERCONCEPTS/funds/*/queries"];
327
+ const excludes = [];
328
+ expect(isMatchUrlPattern(url, includes, excludes)).toBe(true);
329
+ });
324
330
  test("should handle URL patterns with fragments", () => {
325
331
  const url = "https://example.com/dashboard#overview";
326
332
  const includes = ["https://example.com/dashboard#*"];
@@ -243,6 +243,12 @@ describe("URL Condition Evaluation", () => {
243
243
  const excludes = [];
244
244
  expect(isMatchUrlPattern(url, includes, excludes)).toBe(true);
245
245
  });
246
+ test("should handle URL patterns with wildcard in nested path", () => {
247
+ const url = "http://localhost:3004/client-view/sites/SUPERCONCEPTS/funds/aaaa/queries";
248
+ const includes = ["/client-view/sites/SUPERCONCEPTS/funds/*/queries"];
249
+ const excludes = [];
250
+ expect(isMatchUrlPattern(url, includes, excludes)).toBe(true);
251
+ });
246
252
  test("should handle URL patterns with fragments", () => {
247
253
  const url = "https://example.com/dashboard#overview";
248
254
  const includes = ["https://example.com/dashboard#*"];
@@ -22,7 +22,8 @@ var attribute_exports = {};
22
22
  __export(attribute_exports, {
23
23
  capitalizeFirstLetter: () => capitalizeFirstLetter,
24
24
  filterNullAttributes: () => filterNullAttributes,
25
- getAttributeType: () => getAttributeType
25
+ getAttributeType: () => getAttributeType,
26
+ isValidISO8601: () => isValidISO8601
26
27
  });
27
28
  module.exports = __toCommonJS(attribute_exports);
28
29
  var import_types = require("@usertour/types");
@@ -38,46 +39,34 @@ var isNull = (x) => {
38
39
  };
39
40
 
40
41
  // src/attribute.ts
41
- var isValidYear = (date) => {
42
- const year = date.getFullYear();
43
- return year >= 1900 && year <= 2100;
44
- };
45
- var tryParseDate = (parser) => {
46
- try {
47
- const date = parser();
48
- return (0, import_date_fns.isValid)(date) && isValidYear(date);
49
- } catch {
42
+ var isValidISO8601 = (value) => {
43
+ if (typeof value !== "string") {
50
44
  return false;
51
45
  }
52
- };
53
- function isDateString(dateStr) {
54
- if (!Number.isNaN(Number(dateStr)) || dateStr.length < 10) {
46
+ const iso8601Pattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
47
+ if (!iso8601Pattern.test(value)) {
55
48
  return false;
56
49
  }
57
- const dateFormats = [
58
- "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
59
- "yyyy-MM-dd'T'HH:mm:ss'Z'",
60
- "yyyy-MM-dd'T'HH:mm:ss.SSS",
61
- "yyyy-MM-dd'T'HH:mm:ss",
62
- "yyyy-MM-dd",
63
- "MM/dd/yyyy",
64
- "dd/MM/yyyy",
65
- "yyyy/MM/dd",
66
- "MM-dd-yyyy",
67
- "dd-MM-yyyy"
68
- ];
69
- if (tryParseDate(() => (0, import_date_fns.parseISO)(dateStr))) {
70
- return true;
50
+ try {
51
+ const date = (0, import_date_fns.parseISO)(value);
52
+ if (!(0, import_date_fns.isValid)(date)) {
53
+ return false;
54
+ }
55
+ const isoString = date.toISOString();
56
+ const normalizedInput = value.replace(/\.\d{3}Z$/, "Z");
57
+ const normalizedIso = isoString.replace(/\.\d{3}Z$/, "Z");
58
+ return normalizedInput === normalizedIso || value === isoString;
59
+ } catch {
60
+ return false;
71
61
  }
72
- return dateFormats.some((format) => tryParseDate(() => (0, import_date_fns.parse)(dateStr, format, /* @__PURE__ */ new Date())));
73
- }
62
+ };
74
63
  var getAttributeType = (attribute) => {
75
64
  const t = typeof attribute;
76
65
  if (t === "number") {
77
66
  return import_types.BizAttributeTypes.Number;
78
67
  }
79
68
  if (t === "string") {
80
- if (isDateString(attribute)) {
69
+ if (isValidISO8601(attribute)) {
81
70
  return import_types.BizAttributeTypes.DateTime;
82
71
  }
83
72
  return import_types.BizAttributeTypes.String;
@@ -107,5 +96,6 @@ var filterNullAttributes = (attributes) => {
107
96
  0 && (module.exports = {
108
97
  capitalizeFirstLetter,
109
98
  filterNullAttributes,
110
- getAttributeType
99
+ getAttributeType,
100
+ isValidISO8601
111
101
  });
@@ -1,5 +1,21 @@
1
+ /**
2
+ * Validate if a value is a valid ISO 8601 date string in UTC
3
+ * According to the specification: datetime must be stored as ISO 8601 in UTC
4
+ *
5
+ * Following industry best practices (Stripe, GitHub, AWS, etc.), we only accept
6
+ * the 'Z' format for UTC, not '+00:00' or '-00:00', for consistency and simplicity.
7
+ *
8
+ * Why we need additional validation after parseISO:
9
+ * 1. parseISO is lenient - it may parse invalid dates (e.g., "2024-13-45") and return a valid Date object
10
+ * by auto-correcting (e.g., "2024-13-45" becomes "2025-01-14")
11
+ * 2. We need to ensure the input string exactly matches what would be produced by toISOString()
12
+ * This prevents accepting malformed dates that get "fixed" by the parser
13
+ * 3. The regex pattern ensures strict format compliance (must have T and Z)
14
+ * 4. The comparison ensures no date normalization occurred (e.g., invalid month/day corrections)
15
+ */
16
+ declare const isValidISO8601: (value: any) => boolean;
1
17
  declare const getAttributeType: (attribute: any) => number;
2
18
  declare const capitalizeFirstLetter: (string: string) => string;
3
19
  declare const filterNullAttributes: (attributes: Record<string, any>) => Record<string, any>;
4
20
 
5
- export { capitalizeFirstLetter, filterNullAttributes, getAttributeType };
21
+ export { capitalizeFirstLetter, filterNullAttributes, getAttributeType, isValidISO8601 };
@@ -1,5 +1,21 @@
1
+ /**
2
+ * Validate if a value is a valid ISO 8601 date string in UTC
3
+ * According to the specification: datetime must be stored as ISO 8601 in UTC
4
+ *
5
+ * Following industry best practices (Stripe, GitHub, AWS, etc.), we only accept
6
+ * the 'Z' format for UTC, not '+00:00' or '-00:00', for consistency and simplicity.
7
+ *
8
+ * Why we need additional validation after parseISO:
9
+ * 1. parseISO is lenient - it may parse invalid dates (e.g., "2024-13-45") and return a valid Date object
10
+ * by auto-correcting (e.g., "2024-13-45" becomes "2025-01-14")
11
+ * 2. We need to ensure the input string exactly matches what would be produced by toISOString()
12
+ * This prevents accepting malformed dates that get "fixed" by the parser
13
+ * 3. The regex pattern ensures strict format compliance (must have T and Z)
14
+ * 4. The comparison ensures no date normalization occurred (e.g., invalid month/day corrections)
15
+ */
16
+ declare const isValidISO8601: (value: any) => boolean;
1
17
  declare const getAttributeType: (attribute: any) => number;
2
18
  declare const capitalizeFirstLetter: (string: string) => string;
3
19
  declare const filterNullAttributes: (attributes: Record<string, any>) => Record<string, any>;
4
20
 
5
- export { capitalizeFirstLetter, filterNullAttributes, getAttributeType };
21
+ export { capitalizeFirstLetter, filterNullAttributes, getAttributeType, isValidISO8601 };
package/dist/attribute.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  capitalizeFirstLetter,
3
3
  filterNullAttributes,
4
- getAttributeType
5
- } from "./chunk-EEYZG4JJ.js";
4
+ getAttributeType,
5
+ isValidISO8601
6
+ } from "./chunk-R4R6MDTW.js";
6
7
  import "./chunk-GFH3VWOC.js";
7
8
  import "./chunk-XEO3YXBM.js";
8
9
  export {
9
10
  capitalizeFirstLetter,
10
11
  filterNullAttributes,
11
- getAttributeType
12
+ getAttributeType,
13
+ isValidISO8601
12
14
  };